Merge "Adding more standard media sizes." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 10f8c36..5e74712 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20,6 +20,7 @@
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+ field public static final java.lang.String BIND_CALL_SERVICE = "android.permission.BIND_CALL_SERVICE";
field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
@@ -4364,6 +4365,7 @@
method public void clear() throws java.io.IOException;
method public void clearWallpaperOffsets(android.os.IBinder);
method public void forgetLoadedWallpaper();
+ method public android.content.Intent getCropAndSetWallpaperIntent(android.net.Uri);
method public int getDesiredMinimumHeight();
method public int getDesiredMinimumWidth();
method public android.graphics.drawable.Drawable getDrawable();
@@ -4381,6 +4383,7 @@
method public void setWallpaperOffsets(android.os.IBinder, float, float);
method public void suggestDesiredDimensions(int, int);
field public static final java.lang.String ACTION_CHANGE_LIVE_WALLPAPER = "android.service.wallpaper.CHANGE_LIVE_WALLPAPER";
+ field public static final java.lang.String ACTION_CROP_AND_SET_WALLPAPER = "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
field public static final java.lang.String ACTION_LIVE_WALLPAPER_CHOOSER = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
field public static final java.lang.String COMMAND_DROP = "android.home.drop";
field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
@@ -7256,6 +7259,7 @@
field public static final java.lang.String FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus";
field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
+ field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
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";
@@ -10860,6 +10864,7 @@
public abstract class CameraMetadata {
method public abstract T get(android.hardware.camera2.CameraMetadata.Key<T>);
+ method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getKeys();
field public static final int COLOR_CORRECTION_MODE_FAST = 1; // 0x1
field public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0; // 0x0
@@ -10985,6 +10990,8 @@
public final class CameraProperties extends android.hardware.camera2.CameraMetadata {
method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+ method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureRequestKeys();
+ method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureResultKeys();
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_RANGE;
@@ -11129,6 +11136,7 @@
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
+ field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACES;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_IDS;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_LANDMARKS;
@@ -11144,14 +11152,16 @@
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
}
- public static class CaptureResult.Face {
- ctor public CaptureResult.Face();
+ public final class Face {
method public android.graphics.Rect getBounds();
method public int getId();
- method public android.graphics.Point getLeftEye();
- method public android.graphics.Point getMouth();
- method public android.graphics.Point getRightEye();
+ method public android.graphics.Point getLeftEyePosition();
+ method public android.graphics.Point getMouthPosition();
+ method public android.graphics.Point getRightEyePosition();
method public int getScore();
+ field public static final int ID_UNSUPPORTED = -1; // 0xffffffff
+ field public static final int SCORE_MAX = 100; // 0x64
+ field public static final int SCORE_MIN = 1; // 0x1
}
public final class Rational {
@@ -12332,7 +12342,7 @@
field public static final int EULER_Z = 2; // 0x2
}
- public abstract interface Image implements java.lang.AutoCloseable {
+ public abstract class Image implements java.lang.AutoCloseable {
method public abstract void close();
method public abstract int getFormat();
method public abstract int getHeight();
@@ -12341,23 +12351,23 @@
method public abstract int getWidth();
}
- public static abstract interface Image.Plane {
+ public static abstract class Image.Plane {
method public abstract java.nio.ByteBuffer getBuffer();
method public abstract int getPixelStride();
method public abstract int getRowStride();
}
- public final class ImageReader implements java.lang.AutoCloseable {
- ctor public ImageReader(int, int, int, int);
+ public class ImageReader implements java.lang.AutoCloseable {
+ method public android.media.Image acquireLatestImage();
+ method public android.media.Image acquireNextImage();
method public void close();
method public int getHeight();
method public int getImageFormat();
method public int getMaxImages();
- method public android.media.Image getNextImage();
method public android.view.Surface getSurface();
method public int getWidth();
- method public void releaseImage(android.media.Image);
- method public void setImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
+ method public static android.media.ImageReader newInstance(int, int, int, int);
+ method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
}
public static abstract interface ImageReader.OnImageAvailableListener {
@@ -13632,6 +13642,12 @@
field public short numBands;
}
+ public class LoudnessEnhancer extends android.media.audiofx.AudioEffect {
+ method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
+ method public void setTargetGain(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
+ field public static final int PARAM_TARGET_GAIN_MB = 0; // 0x0
+ }
+
public class NoiseSuppressor extends android.media.audiofx.AudioEffect {
method public static android.media.audiofx.NoiseSuppressor create(int);
method public static boolean isAvailable();
@@ -15209,9 +15225,9 @@
field public static final java.lang.String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
field public static final java.lang.String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
- field public static final int FLAG_READER_KOVIO = 16; // 0x10
field public static final int FLAG_READER_NFC_A = 1; // 0x1
field public static final int FLAG_READER_NFC_B = 2; // 0x2
+ field public static final int FLAG_READER_NFC_BARCODE = 16; // 0x10
field public static final int FLAG_READER_NFC_F = 4; // 0x4
field public static final int FLAG_READER_NFC_V = 8; // 0x8
field public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 256; // 0x100
@@ -19166,15 +19182,21 @@
public final class PrintJob {
method public void cancel();
- method public int getId();
+ method public android.print.PrintJobId getId();
method public android.print.PrintJobInfo getInfo();
}
+ public final class PrintJobId implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public final class PrintJobInfo implements android.os.Parcelable {
method public int describeContents();
method public android.print.PrintAttributes getAttributes();
method public int getCopies();
- method public int getId();
+ method public android.print.PrintJobId getId();
method public java.lang.String getLabel();
method public android.print.PageRange[] getPages();
method public android.print.PrinterId getPrinterId();
@@ -19186,6 +19208,7 @@
field public static final int STATE_BLOCKED = 4; // 0x4
field public static final int STATE_CANCELED = 7; // 0x7
field public static final int STATE_COMPLETED = 5; // 0x5
+ field public static final int STATE_CREATED = 1; // 0x1
field public static final int STATE_FAILED = 6; // 0x6
field public static final int STATE_QUEUED = 2; // 0x2
field public static final int STATE_STARTED = 3; // 0x3
@@ -19193,7 +19216,6 @@
public final class PrintManager {
method public java.util.List<android.print.PrintJob> getPrintJobs();
- method public android.print.PrintJob print(java.lang.String, java.io.File, android.print.PrintDocumentInfo, android.print.PrintAttributes);
method public android.print.PrintJob print(java.lang.String, android.print.PrintDocumentAdapter, android.print.PrintAttributes);
}
@@ -19304,7 +19326,7 @@
method public boolean complete();
method public boolean fail(java.lang.String);
method public android.printservice.PrintDocument getDocument();
- method public int getId();
+ method public android.print.PrintJobId getId();
method public android.print.PrintJobInfo getInfo();
method public boolean isBlocked();
method public boolean isCancelled();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index d78572b..c18f542 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -100,6 +100,7 @@
" am monitor [--gdb <port>]\n" +
" am hang [--allow-restart]\n" +
" am restart\n" +
+ " am idle-maintenance\n" +
" am screen-compat [on|off] <PACKAGE>\n" +
" am to-uri [INTENT]\n" +
" am to-intent-uri [INTENT]\n" +
@@ -189,6 +190,8 @@
"\n" +
"am restart: restart the user-space system.\n" +
"\n" +
+ "am idle-maintenance: perform idle maintenance now.\n" +
+ "\n" +
"am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
"\n" +
"am to-uri: print the given Intent specification as a URI.\n" +
@@ -295,6 +298,8 @@
runHang();
} else if (op.equals("restart")) {
runRestart();
+ } else if (op.equals("idle-maintenance")) {
+ runIdleMaintenance();
} else if (op.equals("screen-compat")) {
runScreenCompat();
} else if (op.equals("to-uri")) {
@@ -1393,6 +1398,20 @@
mAm.restart();
}
+ private void runIdleMaintenance() throws Exception {
+ String opt;
+ while ((opt=nextOption()) != null) {
+ System.err.println("Error: Unknown option: " + opt);
+ return;
+ }
+
+ System.out.println("Performing idle maintenance...");
+ Intent intent = new Intent(
+ "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE");
+ mAm.broadcastIntent(null, intent, null, null, 0, null, null, null,
+ android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL);
+ }
+
private void runScreenCompat() throws Exception {
String mode = nextArgRequired();
boolean enabled;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 370db31..a727b07 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1995,6 +1995,13 @@
reply.writeParcelableArray(uris, 0);
return true;
}
+
+ case PERFORM_IDLE_MAINTENANCE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ performIdleMaintenance();
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -4578,5 +4585,15 @@
return uris;
}
+ public void performIdleMaintenance() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(PERFORM_IDLE_MAINTENANCE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b2ae298..25c02df 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -403,6 +403,8 @@
String sourcePackage, String targetPackage, int modeFlags, int modeMask)
throws RemoteException;
+ public void performIdleMaintenance() throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -685,4 +687,5 @@
int REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+176;
int RESTART_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+177;
int GET_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+178;
+ int PERFORM_IDLE_MAINTENANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+179;
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 3342068..2bc7cbf 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,8 +16,11 @@
package android.app;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -30,7 +33,7 @@
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Binder;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -41,13 +44,13 @@
import android.os.ServiceManager;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
/**
* Provides access to the system wallpaper. With WallpaperManager, you can
@@ -62,6 +65,15 @@
private float mWallpaperYStep = -1;
/**
+ * Activity Action: Show settings for choosing wallpaper. Do not use directly to construct
+ * an intent; instead, use {@link #getCropAndSetWallpaperIntent}.
+ * <p>Input: {@link Intent#getData} is the URI of the image to crop and set as wallpaper.
+ * <p>Output: RESULT_OK if user decided to crop/set the wallpaper, RESULT_CANCEL otherwise
+ */
+ public static final String ACTION_CROP_AND_SET_WALLPAPER =
+ "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
+
+ /**
* Launch an activity for the user to pick the current global live
* wallpaper.
*/
@@ -463,7 +475,39 @@
return null;
}
}
-
+
+ /**
+ * Gets an Intent that will launch an activity that crops the given
+ * image and sets the device's wallpaper. If there is a default HOME activity
+ * that supports cropping wallpapers, it will be preferred as the default.
+ * Use this method instead of directly creating a {@link #ACTION_CROP_AND_SET_WALLPAPER}
+ * intent.
+ */
+ public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+ final PackageManager packageManager = mContext.getPackageManager();
+ Intent cropAndSetWallpaperIntent =
+ new Intent(ACTION_CROP_AND_SET_WALLPAPER, imageUri);
+ cropAndSetWallpaperIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ // Find out if the default HOME activity supports CROP_AND_SET_WALLPAPER
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolvedHome = packageManager.resolveActivity(homeIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ if (resolvedHome != null) {
+ cropAndSetWallpaperIntent.setPackage(resolvedHome.activityInfo.packageName);
+
+ List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
+ cropAndSetWallpaperIntent, 0);
+ if (cropAppList.size() > 0) {
+ return cropAndSetWallpaperIntent;
+ }
+ }
+
+ // fallback crop activity
+ cropAndSetWallpaperIntent.setPackage("com.android.wallpapercropper");
+ return cropAndSetWallpaperIntent;
+ }
+
/**
* Change the current system wallpaper to the bitmap in the given resource.
* The resource is opened as a raw data stream and copied into the
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e0b1c00..ab82531 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1372,7 +1372,7 @@
*
* @hide
*/
- public boolean hasAnyCaCertsInstalled() {
+ public static boolean hasAnyCaCertsInstalled() {
TrustedCertificateStore certStore = new TrustedCertificateStore();
Set<String> aliases = certStore.userAliases();
return aliases != null && !aliases.isEmpty();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 92a9c7c..02ccaa5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2132,13 +2132,8 @@
public static final String UPDATE_LOCK_SERVICE = "updatelock";
/**
- * Use with {@link #getSystemService} to retrieve a {@link
- * android.net.NetworkManagementService} for handling management of
- * system network services
- *
+ * Constant for the internal network management service, not really a Context service.
* @hide
- * @see #getSystemService
- * @see android.net.NetworkManagementService
*/
public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
@@ -2327,7 +2322,7 @@
* android.hardware.SerialManager} for access to serial ports.
*
* @see #getSystemService
- * @see android.harware.SerialManager
+ * @see android.hardware.SerialManager
*
* @hide
*/
@@ -2353,17 +2348,6 @@
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.os.SchedulingPolicyService} for managing scheduling policy.
- *
- * @see #getSystemService
- * @see android.os.SchedulingPolicyService
- *
- * @hide
- */
- public static final String SCHEDULING_POLICY_SERVICE = "scheduling_policy";
-
- /**
- * Use with {@link #getSystemService} to retrieve a
* {@link android.os.UserManager} for managing users on devices that support multiple users.
*
* @see #getSystemService
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 416f489..9203af9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1196,6 +1196,13 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports device policy enforcement via device admins.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports WiFi (802.11) networking.
*/
@SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4494e69..2e25177 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1441,18 +1441,29 @@
*/
boolean required = true; // Optional <uses-permission> not supported
+ int maxSdkVersion = 0;
+ TypedValue val = sa.peekValue(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
+ if (val != null) {
+ if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
+ maxSdkVersion = val.data;
+ }
+ }
+
sa.recycle();
- if (name != null) {
- int index = pkg.requestedPermissions.indexOf(name);
- if (index == -1) {
- pkg.requestedPermissions.add(name.intern());
- pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
- } else {
- if (pkg.requestedPermissionsRequired.get(index) != required) {
- outError[0] = "conflicting <uses-permission> entries";
- mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return false;
+ if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
+ if (name != null) {
+ int index = pkg.requestedPermissions.indexOf(name);
+ if (index == -1) {
+ pkg.requestedPermissions.add(name.intern());
+ pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
+ } else {
+ if (pkg.requestedPermissionsRequired.get(index) != required) {
+ outError[0] = "conflicting <uses-permission> entries";
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+ return false;
+ }
}
}
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index ec23f08..7f4ba4f 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -18,12 +18,25 @@
import android.hardware.camera2.impl.CameraMetadataNative;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
/**
* The base class for camera controls and information.
*
+ * <p>
* This class defines the basic key/value map used for querying for camera
* characteristics or capture results, and for setting camera request
* parameters.
+ * </p>
+ *
+ * <p>
+ * All instances of CameraMetadata are immutable. The list of keys with {@link #getKeys()}
+ * never changes, nor do the values returned by any key with {@link #get} throughout
+ * the lifetime of the object.
+ * </p>
*
* @see CameraDevice
* @see CameraManager
@@ -38,9 +51,14 @@
}
/**
- * Get a camera metadata field value. The field definitions can be
+ * Get a camera metadata field value.
+ *
+ * <p>The field definitions can be
* found in {@link CameraProperties}, {@link CaptureResult}, and
- * {@link CaptureRequest}.
+ * {@link CaptureRequest}.</p>
+ *
+ * <p>Querying the value for the same key more than once will return a value
+ * which is equal to the previous queried value.</p>
*
* @throws IllegalArgumentException if the key was not valid
*
@@ -49,6 +67,54 @@
*/
public abstract <T> T get(Key<T> key);
+ /**
+ * Returns a list of the keys contained in this map.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>All values retrieved by a key from this list with {@link #get} are guaranteed to be
+ * non-{@code null}. Each key is only listed once in the list. The order of the keys
+ * is undefined.</p>
+ *
+ * @return List of the keys contained in this map.
+ */
+ public List<Key<?>> getKeys() {
+ return Collections.unmodifiableList(getKeysStatic(this.getClass(), this));
+ }
+
+ /**
+ * Return a list of all the Key<?> that are declared as a field inside of the class
+ * {@code type}.
+ *
+ * <p>
+ * Optionally, if {@code instance} is not null, then filter out any keys with null values.
+ * </p>
+ */
+ /*package*/ static ArrayList<Key<?>> getKeysStatic(Class<? extends CameraMetadata> type,
+ CameraMetadata instance) {
+ ArrayList<Key<?>> keyList = new ArrayList<Key<?>>();
+
+ Field[] fields = type.getDeclaredFields();
+ for (Field field : fields) {
+ if (field.getDeclaringClass().isAssignableFrom(Key.class)) {
+ Key<?> key;
+ try {
+ key = (Key<?>) field.get(instance);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("Can't get IllegalAccessException", e);
+ } catch (IllegalArgumentException e) {
+ throw new AssertionError("Can't get IllegalArgumentException", e);
+ }
+ if (instance == null || instance.get(key) != null) {
+ keyList.add(key);
+ }
+ }
+ }
+
+ return keyList;
+ }
+
public static class Key<T> {
private boolean mHasTag;
diff --git a/core/java/android/hardware/camera2/CameraProperties.java b/core/java/android/hardware/camera2/CameraProperties.java
index 45c009f..58a1ee3 100644
--- a/core/java/android/hardware/camera2/CameraProperties.java
+++ b/core/java/android/hardware/camera2/CameraProperties.java
@@ -18,6 +18,9 @@
import android.hardware.camera2.impl.CameraMetadataNative;
+import java.util.Collections;
+import java.util.List;
+
/**
* <p>The properties describing a
* {@link CameraDevice CameraDevice}.</p>
@@ -32,6 +35,8 @@
public final class CameraProperties extends CameraMetadata {
private final CameraMetadataNative mProperties;
+ private List<Key<?>> mAvailableRequestKeys;
+ private List<Key<?>> mAvailableResultKeys;
/**
* Takes ownership of the passed-in properties object
@@ -46,6 +51,75 @@
return mProperties.get(key);
}
+ /**
+ * Returns the list of keys supported by this {@link CameraDevice} for querying
+ * with a {@link CaptureRequest}.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * <p>Note that there is no {@code getAvailableCameraPropertiesKeys()} -- use
+ * {@link #getKeys()} instead.</p>
+ *
+ * @return List of keys supported by this CameraDevice for CaptureRequests.
+ */
+ public List<Key<?>> getAvailableCaptureRequestKeys() {
+ if (mAvailableRequestKeys == null) {
+ mAvailableRequestKeys = getAvailableKeyList(CaptureRequest.class);
+ }
+ return mAvailableRequestKeys;
+ }
+
+ /**
+ * Returns the list of keys supported by this {@link CameraDevice} for querying
+ * with a {@link CaptureResult}.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * <p>Note that there is no {@code getAvailableCameraPropertiesKeys()} -- use
+ * {@link #getKeys()} instead.</p>
+ *
+ * @return List of keys supported by this CameraDevice for CaptureResults.
+ */
+ public List<Key<?>> getAvailableCaptureResultKeys() {
+ if (mAvailableResultKeys == null) {
+ mAvailableResultKeys = getAvailableKeyList(CaptureResult.class);
+ }
+ return mAvailableResultKeys;
+ }
+
+ /**
+ * Returns the list of keys supported by this {@link CameraDevice} by metadataClass.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * @param metadataClass The subclass of CameraMetadata that you want to get the keys for.
+ *
+ * @return List of keys supported by this CameraDevice for metadataClass.
+ *
+ * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
+ */
+ private <T extends CameraMetadata> List<Key<?>> getAvailableKeyList(Class<T> metadataClass) {
+
+ if (metadataClass.equals(CameraMetadata.class)) {
+ throw new AssertionError(
+ "metadataClass must be a strict subclass of CameraMetadata");
+ } else if (!CameraMetadata.class.isAssignableFrom(metadataClass)) {
+ throw new AssertionError(
+ "metadataClass must be a subclass of CameraMetadata");
+ }
+
+ return Collections.unmodifiableList(getKeysStatic(metadataClass, /*instance*/null));
+ }
+
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* The key entries below this point are generated from metadata
* definitions in /system/media/camera/docs. Do not modify by hand or
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 4608ab9..3ec5ca0 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -176,7 +176,7 @@
*/
public final static class Builder {
- private CaptureRequest mRequest;
+ private final CaptureRequest mRequest;
/**
* Initialize the builder using the template; the request takes
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 3fcd2f9..377e78a 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -51,89 +51,6 @@
return mResults.get(key);
}
- /**
- * Describes a face detected in an image.
- */
- public static class Face {
-
- /**
- * <p>Bounds of the face. A rectangle relative to the sensor's
- * {@link CameraProperties#SENSOR_INFO_ACTIVE_ARRAY_SIZE}, with (0,0)
- * representing the top-left corner of the active array rectangle.</p>
- */
- public Rect getBounds() {
- return mBounds;
- }
-
- /** <p>The confidence level for the detection of the face. The range is 1 to
- * 100. 100 is the highest confidence.</p>
- *
- * <p>Depending on the device, even very low-confidence faces may be
- * listed, so applications should filter out faces with low confidence,
- * depending on the use case. For a typical point-and-shoot camera
- * application that wishes to display rectangles around detected faces,
- * filtering out faces with confidence less than 50 is recommended.</p>
- *
- */
- public int getScore() {
- return mScore;
- }
-
- /**
- * An unique id per face while the face is visible to the tracker. If
- * the face leaves the field-of-view and comes back, it will get a new
- * id. This is an optional field, may not be supported on all devices.
- * If not supported, id will always be set to -1. The optional fields
- * are supported as a set. Either they are all valid, or none of them
- * are.
- */
- public int getId() {
- return mId;
- }
-
- /**
- * The coordinates of the center of the left eye. The coordinates are in
- * the same space as the ones for {@link #getBounds}. This is an
- * optional field, may not be supported on all devices. If not
- * supported, the value will always be set to null. The optional fields
- * are supported as a set. Either they are all valid, or none of them
- * are.
- */
- public Point getLeftEye() {
- return mLeftEye;
- }
-
- /**
- * The coordinates of the center of the right eye. The coordinates are
- * in the same space as the ones for {@link #getBounds}.This is an
- * optional field, may not be supported on all devices. If not
- * supported, the value will always be set to null. The optional fields
- * are supported as a set. Either they are all valid, or none of them
- * are.
- */
- public Point getRightEye() {
- return mRightEye;
- }
-
- /**
- * The coordinates of the center of the mouth. The coordinates are in
- * the same space as the ones for {@link #getBounds}. This is an optional
- * field, may not be supported on all devices. If not supported, the
- * value will always be set to null. The optional fields are supported
- * as a set. Either they are all valid, or none of them are.
- */
- public Point getMouth() {
- return mMouth;
- }
-
- private Rect mBounds;
- private int mScore;
- private int mId;
- private Point mLeftEye;
- private Point mRightEye;
- private Point mMouth;
- }
-
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* The key entries below this point are generated from metadata
* definitions in /system/media/camera/docs. Do not modify by hand or
@@ -1003,4 +920,19 @@
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+ /**
+ * <p>
+ * List of the {@link Face Faces} detected through camera face detection
+ * in this result.
+ * </p>
+ * <p>
+ * Only available if {@link #STATISTICS_FACE_DETECT_MODE} {@code !=}
+ * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_OFF OFF}.
+ * </p>
+ *
+ * @see Face
+ */
+ public static final Key<Face[]> STATISTICS_FACES =
+ new Key<Face[]>("android.statistics.faces", Face[].class);
}
diff --git a/core/java/android/hardware/camera2/Face.java b/core/java/android/hardware/camera2/Face.java
new file mode 100644
index 0000000..6bfc535
--- /dev/null
+++ b/core/java/android/hardware/camera2/Face.java
@@ -0,0 +1,252 @@
+/*
+ * 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 android.hardware.camera2;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Describes a face detected in an image.
+ */
+public final class Face {
+
+ /**
+ * The ID is {@code -1} when the optional set of fields is unsupported.
+ *
+ * @see Face#Face(Rect, int)
+ * @see #getId()
+ */
+ public static final int ID_UNSUPPORTED = -1;
+
+ /**
+ * The minimum possible value for the confidence level.
+ *
+ * @see #getScore()
+ */
+ public static final int SCORE_MIN = 1;
+
+ /**
+ * The maximum possible value for the confidence level.
+ *
+ * @see #getScore()
+ */
+ public static final int SCORE_MAX = 100;
+
+ private final Rect mBounds;
+ private final int mScore;
+ private final int mId;
+ private final Point mLeftEye;
+ private final Point mRightEye;
+ private final Point mMouth;
+
+ /**
+ * Create a new face with all fields set.
+ *
+ * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional.
+ * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+ * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+ * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+ *
+ * @param bounds Bounds of the face.
+ * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+ * @param id A unique ID per face visible to the tracker.
+ * @param leftEyePosition The position of the left eye.
+ * @param rightEyePosition The position of the right eye.
+ * @param mouthPosition The position of the mouth.
+ *
+ * @throws IllegalArgumentException
+ * if bounds is {@code null},
+ * or if the confidence is not in the range of
+ * {@value #SCORE_MIN}-{@value #SCORE_MAX},
+ * or if id is {@value #ID_UNSUPPORTED} and
+ * leftEyePosition/rightEyePosition/mouthPosition aren't all null,
+ * or else if id is negative.
+ *
+ * @hide
+ */
+ public Face(Rect bounds, int score, int id,
+ Point leftEyePosition, Point rightEyePosition, Point mouthPosition) {
+ checkNotNull("bounds", bounds);
+ if (score < SCORE_MIN || score > SCORE_MAX) {
+ throw new IllegalArgumentException("Confidence out of range");
+ } else if (id < 0 && id != ID_UNSUPPORTED) {
+ throw new IllegalArgumentException("Id out of range");
+ }
+ if (id == ID_UNSUPPORTED) {
+ checkNull("leftEyePosition", leftEyePosition);
+ checkNull("rightEyePosition", rightEyePosition);
+ checkNull("mouthPosition", mouthPosition);
+ }
+
+ mBounds = bounds;
+ mScore = score;
+ mId = id;
+ mLeftEye = leftEyePosition;
+ mRightEye = rightEyePosition;
+ mMouth = mouthPosition;
+ }
+
+ /**
+ * Create a new face without the optional fields.
+ *
+ * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional.
+ * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+ * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+ * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+ *
+ * @param bounds Bounds of the face.
+ * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+ *
+ * @throws IllegalArgumentException
+ * if bounds is {@code null},
+ * or if the confidence is not in the range of
+ * {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+ *
+ * @hide
+ */
+ public Face(Rect bounds, int score) {
+ this(bounds, score, ID_UNSUPPORTED,
+ /*leftEyePosition*/null, /*rightEyePosition*/null, /*mouthPosition*/null);
+ }
+
+ /**
+ * Bounds of the face.
+ *
+ * <p>A rectangle relative to the sensor's
+ * {@link CameraProperties#SENSOR_INFO_ACTIVE_ARRAY_SIZE}, with (0,0)
+ * representing the top-left corner of the active array rectangle.</p>
+ *
+ * <p>There is no constraints on the the Rectangle value other than it
+ * is not-{@code null}.</p>
+ */
+ public Rect getBounds() {
+ return mBounds;
+ }
+
+ /**
+ * The confidence level for the detection of the face.
+ *
+ * <p>The range is {@value #SCORE_MIN} to {@value #SCORE_MAX}.
+ * {@value #SCORE_MAX} is the highest confidence.</p>
+ *
+ * <p>Depending on the device, even very low-confidence faces may be
+ * listed, so applications should filter out faces with low confidence,
+ * depending on the use case. For a typical point-and-shoot camera
+ * application that wishes to display rectangles around detected faces,
+ * filtering out faces with confidence less than half of {@value #SCORE_MAX}
+ * is recommended.</p>
+ *
+ * @see #SCORE_MAX
+ * @see #SCORE_MIN
+ */
+ public int getScore() {
+ return mScore;
+ }
+
+ /**
+ * An unique id per face while the face is visible to the tracker.
+ *
+ * <p>
+ * If the face leaves the field-of-view and comes back, it will get a new
+ * id.</p>
+ *
+ * <p>This is an optional field, may not be supported on all devices.
+ * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+ * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+ * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+ *
+ * <p>This value will either be {@value #ID_UNSUPPORTED} or
+ * otherwise greater than {@code 0}.</p>
+ *
+ * @see #ID_UNSUPPORTED
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * The coordinates of the center of the left eye.
+ *
+ * <p>The coordinates are in
+ * the same space as the ones for {@link #getBounds}. This is an
+ * optional field, may not be supported on all devices. If not
+ * supported, the value will always be set to null.
+ * This value will always be null only if {@link #getId()} returns
+ * {@value #ID_UNSUPPORTED}.</p>
+ *
+ * @return The left eye position, or {@code null} if unknown.
+ */
+ public Point getLeftEyePosition() {
+ return mLeftEye;
+ }
+
+ /**
+ * The coordinates of the center of the right eye.
+ *
+ * <p>The coordinates are
+ * in the same space as the ones for {@link #getBounds}.This is an
+ * optional field, may not be supported on all devices. If not
+ * supported, the value will always be set to null.
+ * This value will always be null only if {@link #getId()} returns
+ * {@value #ID_UNSUPPORTED}.</p>
+ *
+ * @return The right eye position, or {@code null} if unknown.
+ */
+ public Point getRightEyePosition() {
+ return mRightEye;
+ }
+
+ /**
+ * The coordinates of the center of the mouth.
+ *
+ * <p>The coordinates are in
+ * the same space as the ones for {@link #getBounds}. This is an optional
+ * field, may not be supported on all devices. If not
+ * supported, the value will always be set to null.
+ * This value will always be null only if {@link #getId()} returns
+ * {@value #ID_UNSUPPORTED}.</p> them are.
+ * </p>
+ *
+ * @return The mouth position, or {@code null} if unknown.
+ */
+ public Point getMouthPosition() {
+ return mMouth;
+ }
+
+ /**
+ * Represent the Face as a string for debugging purposes.
+ */
+ @Override
+ public String toString() {
+ return String.format("{ bounds: %s, score: %s, id: %d, " +
+ "leftEyePosition: %s, rightEyePosition: %s, mouthPosition: %s }",
+ mBounds, mScore, mId, mLeftEye, mRightEye, mMouth);
+ }
+
+ private static void checkNotNull(String name, Object obj) {
+ if (obj == null) {
+ throw new IllegalArgumentException(name + " was required, but it was null");
+ }
+ }
+
+ private static void checkNull(String name, Object obj) {
+ if (obj != null) {
+ throw new IllegalArgumentException(name + " was required to be null, but it wasn't");
+ }
+ }
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 020d7b6..c13438a 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -27,7 +27,6 @@
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Map;
/**
* Implementation of camera metadata marshal/unmarshal across Binder to
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index 2c05c58..d0b3ec4 100644
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -19,6 +19,7 @@
import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
+import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
import android.os.DeadObjectException;
@@ -50,6 +51,7 @@
public static final int EBUSY = -16;
public static final int ENODEV = -19;
public static final int EOPNOTSUPP = -95;
+ public static final int EDQUOT = -122;
private static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
@@ -83,6 +85,9 @@
case EBUSY:
UncheckedThrow.throwAnyException(new CameraRuntimeException(
CAMERA_IN_USE));
+ case EDQUOT:
+ UncheckedThrow.throwAnyException(new CameraRuntimeException(
+ MAX_CAMERAS_IN_USE));
case ENODEV:
UncheckedThrow.throwAnyException(new CameraRuntimeException(
CAMERA_DISCONNECTED));
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 2a18900..486e75a 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -227,9 +227,9 @@
/**
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
- * Setting this flag enables polling for Kovio technology.
+ * Setting this flag enables polling for NfcBarcode technology.
*/
- public static final int FLAG_READER_KOVIO = 0x10;
+ public static final int FLAG_READER_NFC_BARCODE = 0x10;
/**
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index fb6bb2e..4e839c6 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -19,9 +19,11 @@
import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
+import android.print.PrintJobId;
import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
+import android.printservice.PrintServiceInfo;
/**
* Interface for communication with the core print manager service.
@@ -30,12 +32,14 @@
*/
interface IPrintManager {
List<PrintJobInfo> getPrintJobInfos(int appId, int userId);
- PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId);
+ PrintJobInfo getPrintJobInfo(in PrintJobId printJobId, int appId, int userId);
PrintJobInfo print(String printJobName, in IPrintClient client,
in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
int appId, int userId);
- void cancelPrintJob(int printJobId, int appId, int userId);
- void restartPrintJob(int printJobId, int appId, int userId);
+ void cancelPrintJob(in PrintJobId printJobId, int appId, int userId);
+ void restartPrintJob(in PrintJobId printJobId, int appId, int userId);
+
+ List<PrintServiceInfo> getEnabledPrintServices(int userId);
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index 0a77dab..291e81f 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -24,6 +24,8 @@
import android.print.IPrintSpoolerCallbacks;
import android.print.PrinterInfo;
import android.print.PrintAttributes;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
/**
* Interface for communication with the print spooler service.
@@ -33,17 +35,18 @@
* @hide
*/
oneway interface IPrintSpooler {
+ void removeObsoletePrintJobs();
+ void forgetPrintJobs(in List<PrintJobId> printJob);
void getPrintJobInfos(IPrintSpoolerCallbacks callback, in ComponentName componentName,
int state, int appId, int sequence);
- void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback,
+ void getPrintJobInfo(in PrintJobId printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence);
- void createPrintJob(String printJobName, in IPrintClient client,
- in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
- IPrintSpoolerCallbacks callback, int appId, int sequence);
- void setPrintJobState(int printJobId, int status, String error,
+ void createPrintJob(in PrintJobInfo printJob, in IPrintClient client,
+ in IPrintDocumentAdapter printAdapter);
+ void setPrintJobState(in PrintJobId printJobId, int status, String stateReason,
IPrintSpoolerCallbacks callback, int sequence);
- void setPrintJobTag(int printJobId, String tag, IPrintSpoolerCallbacks callback,
+ void setPrintJobTag(in PrintJobId printJobId, String tag, IPrintSpoolerCallbacks callback,
int sequence);
- void writePrintJobData(in ParcelFileDescriptor fd, int printJobId);
+ void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
void setClient(IPrintSpoolerClient client);
}
diff --git a/core/java/android/print/IPrintSpoolerCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl
index 51b5439..45c5332 100644
--- a/core/java/android/print/IPrintSpoolerCallbacks.aidl
+++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl
@@ -28,7 +28,6 @@
*/
oneway interface IPrintSpoolerCallbacks {
void onGetPrintJobInfosResult(in List<PrintJobInfo> printJob, int sequence);
- void onCreatePrintJobResult(in PrintJobInfo printJob, int sequence);
void onCancelPrintJobResult(boolean canceled, int sequence);
void onSetPrintJobStateResult(boolean success, int sequence);
void onSetPrintJobTagResult(boolean success, int sequence);
diff --git a/core/java/android/print/IPrinterDiscoveryObserver.aidl b/core/java/android/print/IPrinterDiscoveryObserver.aidl
index b558011..2be7b6b 100644
--- a/core/java/android/print/IPrinterDiscoveryObserver.aidl
+++ b/core/java/android/print/IPrinterDiscoveryObserver.aidl
@@ -18,6 +18,7 @@
import android.print.PrinterId;
import android.print.PrinterInfo;
+import android.content.pm.ParceledListSlice;
/**
* Interface for observing discovered printers by a discovery session.
@@ -25,6 +26,6 @@
* @hide
*/
oneway interface IPrinterDiscoveryObserver {
- void onPrintersAdded(in List<PrinterInfo> printers);
- void onPrintersRemoved(in List<PrinterId> printerIds);
+ void onPrintersAdded(in ParceledListSlice printers);
+ void onPrintersRemoved(in ParceledListSlice printerIds);
}
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 42bea6d..00ade07 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -22,8 +22,6 @@
*/
public final class PrintJob {
- private final int mId;
-
private final PrintManager mPrintManager;
private PrintJobInfo mCachedInfo;
@@ -31,7 +29,6 @@
PrintJob(PrintJobInfo info, PrintManager printManager) {
mCachedInfo = info;
mPrintManager = printManager;
- mId = info.getId();
}
/**
@@ -39,8 +36,8 @@
*
* @return The id.
*/
- public int getId() {
- return mId;
+ public PrintJobId getId() {
+ return mCachedInfo.getId();
}
/**
@@ -57,7 +54,7 @@
if (isInImmutableState()) {
return mCachedInfo;
}
- PrintJobInfo info = mPrintManager.getPrintJobInfo(mId);
+ PrintJobInfo info = mPrintManager.getPrintJobInfo(mCachedInfo.getId());
if (info != null) {
mCachedInfo = info;
}
@@ -69,7 +66,7 @@
*/
public void cancel() {
if (!isInImmutableState()) {
- mPrintManager.cancelPrintJob(mId);
+ mPrintManager.cancelPrintJob(mCachedInfo.getId());
}
}
@@ -91,11 +88,11 @@
return false;
}
PrintJob other = (PrintJob) obj;
- return mId == other.mId;
+ return mCachedInfo.getId().equals(other.mCachedInfo.getId());
}
@Override
public int hashCode() {
- return mId;
+ return mCachedInfo.getId().hashCode();
}
}
diff --git a/core/res/res/values-land/refs.xml b/core/java/android/print/PrintJobId.aidl
similarity index 75%
rename from core/res/res/values-land/refs.xml
rename to core/java/android/print/PrintJobId.aidl
index cda38cf..759f25f 100644
--- a/core/res/res/values-land/refs.xml
+++ b/core/java/android/print/PrintJobId.aidl
@@ -1,5 +1,4 @@
-<?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");
@@ -13,8 +12,8 @@
* WITHOUT 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 type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources>
\ No newline at end of file
+ */
+
+package android.print;
+
+parcelable PrintJobId;
diff --git a/core/java/android/print/PrintJobId.java b/core/java/android/print/PrintJobId.java
new file mode 100644
index 0000000..01550e2
--- /dev/null
+++ b/core/java/android/print/PrintJobId.java
@@ -0,0 +1,122 @@
+/*
+ * 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 android.print;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.UUID;
+
+/**
+ * This class represents the id of a print job.
+ */
+public final class PrintJobId implements Parcelable {
+ private final String mValue;
+
+ /**
+ * Creates a new instance.
+ *
+ * @hide
+ */
+ public PrintJobId() {
+ this(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param value The internal value.
+ *
+ * @hide
+ */
+ public PrintJobId(String value) {
+ mValue = value;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mValue != null) ? mValue.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PrintJobId other = (PrintJobId) obj;
+ if (!TextUtils.equals(mValue, other.mValue)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mValue);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Flattens this id to a string.
+ *
+ * @return The flattened id.
+ *
+ * @hide
+ */
+ public String flattenToString() {
+ return mValue;
+ }
+
+ /**
+ * Unflattens a print job id from a string.
+ *
+ * @string The string.
+ * @return The unflattened id, or null if the string is malformed.
+ *
+ * @hide
+ */
+ public static PrintJobId unflattenFromString(String string) {
+ return new PrintJobId(string);
+ }
+
+ public static final Parcelable.Creator<PrintJobId> CREATOR =
+ new Parcelable.Creator<PrintJobId>() {
+ @Override
+ public PrintJobId createFromParcel(Parcel parcel) {
+ return new PrintJobId(parcel.readString());
+ }
+
+ @Override
+ public PrintJobId[] newArray(int size) {
+ return new PrintJobId[size];
+ }
+ };
+}
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index b919ad6..502a9f2 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -56,8 +56,6 @@
* <p>
* Next valid states: {@link #STATE_QUEUED}
* </p>
- *
- * @hide
*/
public static final int STATE_CREATED = 1;
@@ -117,7 +115,7 @@
public static final int STATE_CANCELED = 7;
/** The unique print job id. */
- private int mId;
+ private PrintJobId mId;
/** The human readable print job label. */
private String mLabel;
@@ -178,7 +176,7 @@
}
private PrintJobInfo(Parcel parcel) {
- mId = parcel.readInt();
+ mId = parcel.readParcelable(null);
mLabel = parcel.readString();
mPrinterId = parcel.readParcelable(null);
mPrinterName = parcel.readString();
@@ -208,7 +206,7 @@
*
* @return The id.
*/
- public int getId() {
+ public PrintJobId getId() {
return mId;
}
@@ -219,7 +217,7 @@
*
* @hide
*/
- public void setId(int id) {
+ public void setId(PrintJobId id) {
this.mId = id;
}
@@ -485,7 +483,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeInt(mId);
+ parcel.writeParcelable(mId, flags);
parcel.writeString(mLabel);
parcel.writeParcelable(mPrinterId, flags);
parcel.writeString(mPrinterName);
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 6e32c05..5429155 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -28,6 +28,7 @@
import android.os.RemoteException;
import android.print.PrintDocumentAdapter.LayoutResultCallback;
import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.printservice.PrintServiceInfo;
import android.text.TextUtils;
import android.util.Log;
@@ -35,7 +36,6 @@
import libcore.io.IoUtils;
-import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
@@ -113,7 +113,7 @@
return new PrintManager(mContext, mService, userId, APP_ID_ANY);
}
- PrintJobInfo getPrintJobInfo(int printJobId) {
+ PrintJobInfo getPrintJobInfo(PrintJobId printJobId) {
try {
return mService.getPrintJobInfo(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
@@ -147,7 +147,7 @@
return Collections.emptyList();
}
- void cancelPrintJob(int printJobId) {
+ void cancelPrintJob(PrintJobId printJobId) {
try {
mService.cancelPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
@@ -156,24 +156,6 @@
}
/**
- * Creates a print job for printing a file with default print attributes.
- *
- * @param printJobName A name for the new print job.
- * @param pdfFile The PDF file to print.
- * @param documentInfo Information about the printed document.
- * @param attributes The default print job attributes.
- * @return The created print job on success or null on failure.
- *
- * @see PrintJob
- */
- public PrintJob print(String printJobName, File pdfFile, PrintDocumentInfo documentInfo,
- PrintAttributes attributes) {
- PrintFileDocumentAdapter documentAdapter = new PrintFileDocumentAdapter(
- mContext, pdfFile, documentInfo);
- return print(printJobName, documentAdapter, attributes);
- }
-
- /**
* Creates a print job for printing a {@link PrintDocumentAdapter} with default print
* attributes.
*
@@ -204,6 +186,25 @@
}
/**
+ * Gets the list of enabled print services.
+ *
+ * @return The enabled service list or an empty list.
+ *
+ * @hide
+ */
+ public List<PrintServiceInfo> getEnabledPrintServices() {
+ try {
+ List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId);
+ if (enabledServices != null) {
+ return enabledServices;
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error getting the enalbed print services", re);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
* @hide
*/
public PrinterDiscoverySession createPrinterDiscoverySession() {
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index 64249b4..c6dbc16 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -17,6 +17,7 @@
package android.print;
import android.content.Context;
+import android.content.pm.ParceledListSlice;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -270,20 +271,22 @@
}
@Override
- public void onPrintersAdded(List<PrinterInfo> printers) {
+ @SuppressWarnings("rawtypes")
+ public void onPrintersAdded(ParceledListSlice printers) {
PrinterDiscoverySession session = mWeakSession.get();
if (session != null) {
session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
- printers).sendToTarget();
+ printers.getList()).sendToTarget();
}
}
@Override
- public void onPrintersRemoved(List<PrinterId> printerIds) {
+ @SuppressWarnings("rawtypes")
+ public void onPrintersRemoved(ParceledListSlice printerIds) {
PrinterDiscoverySession session = mWeakSession.get();
if (session != null) {
session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
- printerIds).sendToTarget();
+ printerIds.getList()).sendToTarget();
}
}
}
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index ad3c04f..c2dfc30 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -20,6 +20,8 @@
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
+import android.print.PrintJobId;
+import android.content.pm.ParceledListSlice;
/**
* The top-level interface from a print service to the system.
@@ -28,11 +30,11 @@
*/
interface IPrintServiceClient {
List<PrintJobInfo> getPrintJobInfos();
- PrintJobInfo getPrintJobInfo(int printJobId);
- boolean setPrintJobState(int printJobId, int state, String error);
- boolean setPrintJobTag(int printJobId, String tag);
- oneway void writePrintJobData(in ParcelFileDescriptor fd, int printJobId);
+ PrintJobInfo getPrintJobInfo(in PrintJobId printJobId);
+ boolean setPrintJobState(in PrintJobId printJobId, int state, String error);
+ boolean setPrintJobTag(in PrintJobId printJobId, String tag);
+ oneway void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
- void onPrintersAdded(in List<PrinterInfo> printers);
- void onPrintersRemoved(in List<PrinterId> printerIds);
+ void onPrintersAdded(in ParceledListSlice printers);
+ void onPrintersRemoved(in ParceledListSlice printerIds);
}
diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java
index 8292cfbc..e43f2a8 100644
--- a/core/java/android/printservice/PrintDocument.java
+++ b/core/java/android/printservice/PrintDocument.java
@@ -19,6 +19,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
import android.util.Log;
import java.io.IOException;
@@ -35,13 +36,13 @@
private static final String LOG_TAG = "PrintDocument";
- private final int mPrintJobId;
+ private final PrintJobId mPrintJobId;
private final IPrintServiceClient mPrintServiceClient;
private final PrintDocumentInfo mInfo;
- PrintDocument(int printJobId, IPrintServiceClient printServiceClient,
+ PrintDocument(PrintJobId printJobId, IPrintServiceClient printServiceClient,
PrintDocumentInfo info) {
mPrintJobId = printJobId;
mPrintServiceClient = printServiceClient;
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 4ff7f0c..2fcae6b 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -17,6 +17,7 @@
package android.printservice;
import android.os.RemoteException;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.text.TextUtils;
import android.util.Log;
@@ -52,7 +53,7 @@
*
* @return The id.
*/
- public int getId() {
+ public PrintJobId getId() {
PrintService.throwIfNotCalledOnMainThread();
return mCachedInfo.getId();
}
@@ -312,12 +313,12 @@
return false;
}
PrintJob other = (PrintJob) obj;
- return (mCachedInfo.getId() == other.mCachedInfo.getId());
+ return (mCachedInfo.getId().equals(other.mCachedInfo.getId()));
}
@Override
public int hashCode() {
- return mCachedInfo.getId();
+ return mCachedInfo.getId().hashCode();
}
private boolean isInImmutableState() {
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 012e76ab..e5ebf77 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -178,6 +178,14 @@
* For detailed configuration options that can be specified via the meta-data
* refer to {@link android.R.styleable#PrintService android.R.styleable.PrintService}.
* </p>
+ * <p>
+ * If you declare a settings or add a printers activity, they have to be exported,
+ * by setting the {@link android.R.attr#exported} activity attribute to <code>true
+ * </code>. Also in case you want only the system to be able to start any of these
+ * activities you can specify that they request the android.permission
+ * .START_PRINT_SERVICE_CONFIG_ACTIVITY permission by setting the
+ * {@link android.R.attr#permission} activity attribute.
+ * </p>
*/
public static final String SERVICE_META_DATA = "android.printservice";
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index b0bf3da..17cb68f 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
@@ -80,8 +81,6 @@
public abstract class PrinterDiscoverySession {
private static final String LOG_TAG = "PrinterDiscoverySession";
- private static final int MAX_ITEMS_PER_CALLBACK = 50;
-
private static int sIdCounter = 0;
private final int mId;
@@ -112,7 +111,11 @@
// If some printers were added in the method that
// created the session, send them over.
if (!mPrinters.isEmpty()) {
- sendAddedPrinters(mObserver, getPrinters());
+ try {
+ mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(getPrinters()));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending added printers", re);
+ }
}
}
@@ -184,7 +187,11 @@
// Send the added printers, if such.
if (addedPrinters != null) {
- sendAddedPrinters(mObserver, addedPrinters);
+ try {
+ mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(addedPrinters));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending added printers", re);
+ }
}
} else {
// Remember the last sent printers if needed.
@@ -203,27 +210,6 @@
}
}
- private static void sendAddedPrinters(IPrintServiceClient observer,
- List<PrinterInfo> printers) {
- try {
- final int printerCount = printers.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersAdded(printers);
- } else {
- // Send the added printers in chunks avoiding the binder transaction limit.
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterInfo> subPrinters = printers.subList(start, end);
- observer.onPrintersAdded(subPrinters);
- }
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending added printers", re);
- }
- }
-
/**
* Removes added printers. Removing an already removed or never added
* printer has no effect. Removed printers can be added again. You can
@@ -261,7 +247,12 @@
// Send the removed printers, if such.
if (!removedPrinterIds.isEmpty()) {
- sendRemovedPrinters(mObserver, removedPrinterIds);
+ try {
+ mObserver.onPrintersRemoved(new ParceledListSlice<PrinterId>(
+ removedPrinterIds));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending removed printers", re);
+ }
}
} else {
// Remember the last sent printers if needed.
@@ -278,26 +269,6 @@
}
}
- private static void sendRemovedPrinters(IPrintServiceClient observer,
- List<PrinterId> printerIds) {
- try {
- final int printerIdCount = printerIds.size();
- if (printerIdCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersRemoved(printerIds);
- } else {
- final int transactionCount = (printerIdCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerIdCount);
- List<PrinterId> subPrinterIds = printerIds.subList(start, end);
- observer.onPrintersRemoved(subPrinterIds);
- }
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending removed printers", re);
- }
- }
-
private void sendOutOfDiscoveryPeriodPrinterChanges() {
// Noting changed since the last discovery period - nothing to do.
if (mLastSentPrinters == null || mLastSentPrinters.isEmpty()) {
@@ -319,7 +290,11 @@
// Send the added printers, if such.
if (addedPrinters != null) {
- sendAddedPrinters(mObserver, addedPrinters);
+ try {
+ mObserver.onPrintersAdded(new ParceledListSlice<PrinterInfo>(addedPrinters));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending added printers", re);
+ }
}
// Determine the removed printers.
@@ -335,7 +310,11 @@
// Send the removed printers, if such.
if (removedPrinterIds != null) {
- sendRemovedPrinters(mObserver, removedPrinterIds);
+ try {
+ mObserver.onPrintersRemoved(new ParceledListSlice<PrinterId>(removedPrinterIds));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error sending removed printers", re);
+ }
}
mLastSentPrinters = null;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index af905b4..c8312e3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -160,6 +160,38 @@
"android.settings.SECURITY_SETTINGS";
/**
+ * Activity Action: Show trusted credentials settings, opening to the user tab,
+ * to allow management of installed credentials.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_TRUSTED_CREDENTIALS_USER =
+ "com.android.settings.TRUSTED_CREDENTIALS_USER";
+
+ /**
+ * Activity Action: Show dialog explaining that an installed CA cert may enable
+ * monitoring of encrypted network traffic.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MONITORING_CERT_INFO =
+ "com.android.settings.MONITORING_CERT_INFO";
+
+ /**
* Activity Action: Show settings to allow configuration of privacy options.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -4333,6 +4365,9 @@
/** @hide */
public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
+ /** @hide */
+ public static final String TRANSIENT_NAV_CONFIRMATIONS = "transient_nav_confirmations";
+
/**
* This are the settings to be backed up.
*
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index 12e0d73..4cc2c42 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -91,6 +91,9 @@
return null;
}
final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
+ if (DBG) {
+ Log.d(LOG_TAG, "Created animator " + anim);
+ }
if (listener != null) {
anim.addListener(listener);
anim.addPauseListener(listener);
@@ -146,12 +149,41 @@
final View endView = endValues.view;
if (DBG) {
View startView = (startValues != null) ? startValues.view : null;
- Log.d(LOG_TAG, "Fade.onDisappear: startView, startVis, endView, endVis = " +
+ Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
}
// if alpha < 1, just fade it in from the current value
if (endView.getAlpha() == 1.0f) {
endView.setAlpha(0);
+ TransitionListener transitionListener = new TransitionListenerAdapter() {
+ boolean mCanceled = false;
+ float mPausedAlpha;
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ endView.setAlpha(1);
+ mCanceled = true;
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ if (!mCanceled) {
+ endView.setAlpha(1);
+ }
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ mPausedAlpha = endView.getAlpha();
+ endView.setAlpha(1);
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ endView.setAlpha(mPausedAlpha);
+ }
+ };
+ addListener(transitionListener);
}
return createAnimation(endView, endView.getAlpha(), 1, null);
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index c588c6b..60b4708 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1240,12 +1240,13 @@
View oldView = oldInfo.view;
TransitionValues newValues = mEndValues.viewValues != null ?
mEndValues.viewValues.get(oldView) : null;
+ if (newValues == null) {
+ newValues = mEndValues.idValues.get(oldView.getId());
+ }
if (oldValues != null) {
// if oldValues null, then transition didn't care to stash values,
// and won't get canceled
- if (newValues == null) {
- cancel = true;
- } else {
+ if (newValues != null) {
for (String key : oldValues.values.keySet()) {
Object oldValue = oldValues.values.get(key);
Object newValue = newValues.values.get(key);
@@ -1451,6 +1452,8 @@
try {
clone = (Transition) super.clone();
clone.mAnimators = new ArrayList<Animator>();
+ clone.mStartValues = new TransitionValuesMaps();
+ clone.mEndValues = new TransitionValuesMaps();
} catch (CloneNotSupportedException e) {}
return clone;
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 54d801e..44ca4e5 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -22,6 +22,7 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
@@ -68,8 +69,9 @@
ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
- private static ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>> sRunningTransitions =
- new ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>>();
+ private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
+ sRunningTransitions =
+ new ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>();
private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();
@@ -184,20 +186,24 @@
}
private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
- ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
+ WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions =
sRunningTransitions.get();
- if (runningTransitions == null) {
- runningTransitions = new ArrayMap<ViewGroup, ArrayList<Transition>>();
+ if (runningTransitions == null || runningTransitions.get() == null) {
+ ArrayMap<ViewGroup, ArrayList<Transition>> transitions =
+ new ArrayMap<ViewGroup, ArrayList<Transition>>();
+ runningTransitions = new WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>(
+ transitions);
sRunningTransitions.set(runningTransitions);
}
- return runningTransitions;
+ return runningTransitions.get();
}
private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
final Transition transition) {
if (transition != null) {
final ViewTreeObserver observer = sceneRoot.getViewTreeObserver();
- observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ final ViewTreeObserver.OnPreDrawListener listener =
+ new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
sPendingTransitions.remove(sceneRoot);
@@ -236,7 +242,8 @@
// values set on them again and avoid artifacts.
return false;
}
- });
+ };
+ observer.addOnPreDrawListener(listener);
}
}
@@ -342,23 +349,19 @@
* value of null causes the TransitionManager to use the default transition.
*/
public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) {
-
- // TEMPORARY: disabling delayed transitions until a fix for the various ActionBar-
- // triggered artifacts is found
-
-// if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) {
-// if (Transition.DBG) {
-// Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
-// sceneRoot + ", " + transition);
-// }
-// sPendingTransitions.add(sceneRoot);
-// if (transition == null) {
-// transition = sDefaultTransition;
-// }
-// final Transition finalTransition = transition.clone();
-// sceneChangeSetup(sceneRoot, transition);
-// Scene.setCurrentScene(sceneRoot, null);
-// sceneChangeRunTransition(sceneRoot, finalTransition);
-// }
+ if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) {
+ if (Transition.DBG) {
+ Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
+ sceneRoot + ", " + transition);
+ }
+ sPendingTransitions.add(sceneRoot);
+ if (transition == null) {
+ transition = sDefaultTransition;
+ }
+ final Transition transitionClone = transition.clone();
+ sceneChangeSetup(sceneRoot, transitionClone);
+ Scene.setCurrentScene(sceneRoot, null);
+ sceneChangeRunTransition(sceneRoot, transitionClone);
+ }
}
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 75d3e7c..f49821f 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -65,9 +65,6 @@
ViewGroup endParent;
}
- // Temporary structure, used in calculating state in setup() and play()
- private VisibilityInfo mTmpVisibilityInfo = new VisibilityInfo();
-
@Override
public String[] getTransitionProperties() {
return sTransitionProperties;
@@ -161,7 +158,7 @@
private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
TransitionValues endValues) {
- final VisibilityInfo visInfo = mTmpVisibilityInfo;
+ final VisibilityInfo visInfo = new VisibilityInfo();
visInfo.visibilityChange = false;
visInfo.fadeIn = false;
if (startValues != null) {
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 107d2c6..67a94be 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -702,7 +702,9 @@
@Override
public void run() {
mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mView.buildLayer();
+ if (mView.isAttachedToWindow()) {
+ mView.buildLayer();
+ }
}
};
final int currentLayerType = mView.getLayerType();
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 730c4eb..ad8b51d 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -992,6 +992,8 @@
mData = mDataCopy;
}
mDataCopy = null;
+ mAccess.mData.clear();
+ mAccess.mSize = 0;
}
int size() {
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 91c47d1..76b8579 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -30,6 +30,8 @@
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -41,6 +43,7 @@
FrameLayout mContent;
int mCount;
final Handler mHandler = new Handler();
+ static final int BGCOLOR = 0xffed1d24;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -53,6 +56,7 @@
Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL);
mContent = new FrameLayout(this);
+ mContent.setBackgroundColor(0xC0000000);
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
@@ -64,13 +68,16 @@
logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
logo.setVisibility(View.INVISIBLE);
+ final View bg = new View(this);
+ bg.setBackgroundColor(BGCOLOR);
+ bg.setAlpha(0f);
+
final TextView letter = new TextView(this);
letter.setTypeface(bold);
letter.setTextSize(300);
letter.setTextColor(0xFFFFFFFF);
letter.setGravity(Gravity.CENTER);
- letter.setShadowLayer(12*metrics.density, 0, 0, 0xC085F985);
letter.setText(String.valueOf(Build.VERSION.RELEASE).substring(0, 1));
final int p = (int)(4 * metrics.density);
@@ -81,11 +88,11 @@
tv.setPadding(p, p, p, p);
tv.setTextColor(0xFFFFFFFF);
tv.setGravity(Gravity.CENTER);
- tv.setShadowLayer(4 * metrics.density, 0, 2 * metrics.density, 0x66000000);
tv.setTransformationMethod(new AllCapsTransformationMethod(this));
tv.setText("Android " + Build.VERSION.RELEASE);
tv.setVisibility(View.INVISIBLE);
+ mContent.addView(bg);
mContent.addView(letter, lp);
mContent.addView(logo, lp);
@@ -96,24 +103,54 @@
mContent.addView(tv, lp2);
mContent.setOnClickListener(new View.OnClickListener() {
+ int clicks;
@Override
public void onClick(View v) {
- if (logo.getVisibility() != View.VISIBLE) {
- letter.animate().alpha(0.25f).scaleY(0.75f).scaleX(0.75f).setDuration(2000)
- .start();
- logo.setAlpha(0f);
- logo.setVisibility(View.VISIBLE);
- logo.animate().alpha(1f).setDuration(1000).setStartDelay(500).start();
- tv.setAlpha(0f);
- tv.setVisibility(View.VISIBLE);
- tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
+ clicks++;
+ if (clicks >= 6) {
+ mContent.performLongClick();
+ return;
}
+ letter.animate().cancel();
+ final float offset = (int)letter.getRotation() % 360;
+ letter.animate()
+ .rotationBy((Math.random() > 0.5f ? 360 : -360) - offset)
+ .setInterpolator(new DecelerateInterpolator())
+ .setDuration(700).start();
}
});
mContent.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
+ if (logo.getVisibility() != View.VISIBLE) {
+ bg.setScaleX(0.01f);
+ bg.animate().alpha(1f).scaleX(1f).setStartDelay(500).start();
+ letter.animate().alpha(0f).scaleY(0.5f).scaleX(0.5f)
+ .rotationBy(360)
+ .setInterpolator(new AccelerateInterpolator())
+ .setDuration(1000)
+ .start();
+ logo.setAlpha(0f);
+ logo.setVisibility(View.VISIBLE);
+ logo.setScaleX(0.5f);
+ logo.setScaleY(0.5f);
+ logo.animate().alpha(1f).scaleX(1f).scaleY(1f)
+ .setDuration(1000).setStartDelay(500)
+ .setInterpolator(new AnticipateOvershootInterpolator())
+ .start();
+ tv.setAlpha(0f);
+ tv.setVisibility(View.VISIBLE);
+ tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
+ return true;
+ }
+ return false;
+ }
+ });
+
+ logo.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
try {
startActivity(new Intent(Intent.ACTION_MAIN)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 07854e2..d3fe34e 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -24,6 +24,7 @@
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -969,6 +970,7 @@
if (ps.isInUse()) {
uids.valueAt(iu).resetSafely(now);
} else {
+ uids.valueAt(iu).makeDead();
uids.removeAt(iu);
}
}
@@ -986,6 +988,7 @@
if (ps.isInUse() || ps.mCommonProcess.isInUse()) {
pkgState.mProcesses.valueAt(iproc).resetSafely(now);
} else {
+ pkgState.mProcesses.valueAt(iproc).makeDead();
pkgState.mProcesses.removeAt(iproc);
}
}
@@ -2127,6 +2130,7 @@
int mNumExcessiveCpu;
boolean mMultiPackage;
+ boolean mDead;
public long mTmpTotalTime;
@@ -2230,6 +2234,18 @@
mNumExcessiveCpu = 0;
}
+ void makeDead() {
+ mDead = true;
+ }
+
+ private void ensureNotDead() {
+ if (!mDead) {
+ return;
+ }
+ throw new IllegalStateException("ProcessState dead: name=" + mName
+ + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+ }
+
void writeToParcel(Parcel out, long now) {
out.writeInt(mMultiPackage ? 1 : 0);
out.writeInt(mDurationsTableSize);
@@ -2271,6 +2287,7 @@
}
public void makeActive() {
+ ensureNotDead();
mActive = true;
}
@@ -2279,7 +2296,8 @@
}
public boolean isInUse() {
- return mActive || mNumActiveServices > 0 || mNumStartedServices > 0;
+ return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
+ || mCurState != STATE_NOTHING;
}
/**
@@ -2315,6 +2333,7 @@
}
void setState(int state, long now) {
+ ensureNotDead();
if (mCurState != state) {
//Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
commitStateTime(now);
@@ -2392,6 +2411,7 @@
}
public void addPss(long pss, long uss, boolean always) {
+ ensureNotDead();
if (!always) {
if (mLastPssState == mCurState && SystemClock.uptimeMillis()
< (mLastPssTime+(30*1000))) {
@@ -2453,6 +2473,7 @@
}
public void reportExcessiveWake(ArrayMap<String, ProcessState> pkgList) {
+ ensureNotDead();
mCommonProcess.mNumExcessiveWake++;
if (!mCommonProcess.mMultiPackage) {
return;
@@ -2464,6 +2485,7 @@
}
public void reportExcessiveCpu(ArrayMap<String, ProcessState> pkgList) {
+ ensureNotDead();
mCommonProcess.mNumExcessiveCpu++;
if (!mCommonProcess.mMultiPackage) {
return;
@@ -2489,9 +2511,17 @@
return this;
}
- private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList,
- int index) {
+ private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList, int index) {
ProcessState proc = pkgList.valueAt(index);
+ if (mDead && proc.mCommonProcess != proc) {
+ // Somehow we try to continue to use a process state that is dead, because
+ // it was not being told it was active during the last commit. We can recover
+ // from this by generating a fresh new state, but this is bad because we
+ // are losing whatever data we had in the old process state.
+ Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
+ + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+ proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mName);
+ }
if (proc.mMultiPackage) {
// The array map is still pointing to a common process state
// that is now shared across packages. Update it to point to
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 2d06b68..f773f59 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -159,17 +159,26 @@
}
-static SkMemoryStream* adaptor_to_mem_stream(SkStream* adaptor) {
- SkASSERT(adaptor != NULL);
- SkDynamicMemoryWStream wStream;
- const int bufferSize = 256 * 1024; // 256 KB, same as ViewStateSerializer.
- uint8_t buffer[bufferSize];
- do {
- size_t bytesRead = adaptor->read(buffer, bufferSize);
- wStream.write(buffer, bytesRead);
- } while (!adaptor->isAtEnd());
- SkAutoTUnref<SkData> data(wStream.copyToData());
- return new SkMemoryStream(data.get());
+static SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) {
+ SkASSERT(stream != NULL);
+ size_t bufferSize = 4096;
+ size_t streamLen = 0;
+ size_t len;
+ char* data = (char*)sk_malloc_throw(bufferSize);
+
+ while ((len = stream->read(data + streamLen,
+ bufferSize - streamLen)) != 0) {
+ streamLen += len;
+ if (streamLen == bufferSize) {
+ bufferSize *= 2;
+ data = (char*)sk_realloc_throw(data, bufferSize);
+ }
+ }
+ data = (char*)sk_realloc_throw(data, streamLen);
+
+ SkMemoryStream* streamMem = new SkMemoryStream();
+ streamMem->setMemoryOwned(data, streamLen);
+ return streamMem;
}
SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 499a930..c2a830d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1103,6 +1103,13 @@
android:description="@string/permdesc_use_sip"
android:label="@string/permlab_use_sip" />
+ <!-- Allows an application to request CallHandlerService implementations. -->
+ <permission android:name="android.permission.BIND_CALL_SERVICE"
+ android:permissionGroup="android.permission-group.PHONE_CALLS"
+ android:protectionLevel="system|signature"
+ android:description="@string/permdesc_bind_call_service"
+ android:label="@string/permlab_bind_call_service" />
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
<!-- ================================== -->
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb_am.png b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
index 0c13339..382557e 100644
--- a/core/res/res/drawable-hdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_certificate_info.png b/core/res/res/drawable-hdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..3be426c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb_am.png b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
index f0a5089..4380035 100644
--- a/core/res/res/drawable-mdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_certificate_info.png b/core/res/res/drawable-mdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..e15cf38
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index 4fd0e3c..6351c2d 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
index 789a3f5..3222a76 100644
--- a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png b/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..3c93ea0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
index a36fa36..e01ad386 100644
--- a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png b/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..d96ef64
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/layout/toast_bar.xml b/core/res/res/layout/toast_bar.xml
index b7443d5..a31d7cb 100644
--- a/core/res/res/layout/toast_bar.xml
+++ b/core/res/res/layout/toast_bar.xml
@@ -35,7 +35,7 @@
android:paddingRight="16dp"
android:singleLine="true"
android:textColor="@android:color/white"
- android:textSize="16sp" />
+ android:textSize="14sp" />
<LinearLayout
android:id="@android:id/button1"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 9935053..49b2bdc 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel <xliff:g id="CONTENT_TYPE">%s</xliff:g> uitgevee."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Foon se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan dalk gemonitor word"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Ek"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet-opsies"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Foonopsies"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Laat die program toe om laevlak-kenmerke van Wi-Fi-skerms te beheer."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"vang oudio-uitset vas"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Laat die program oudio-uitset vasvang en herlei."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Aktiveerwoord-opsporing"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Laat die program toe om oudio vir Aktiveerwoord-opsporing op te neem. Die opname kan in die agtergrond plaasvind, maar verhoed nie dat ander oudio opgeneem word nie (bv. Kameraopnemer)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"vang video-uitset vas"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Laat die program video-uitset vasvang en herlei."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"vang veilige video-uitset vas"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"verhoed foon om te slaap"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Laat die program toe om die tablet te keer om te slaap."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Laat die program toe om die foon te keer om te slaap."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"versend infrarooi"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Laat die program toe om die tablet se infrarooisender te gebruik."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Laat die program toe om die foon se infrarooisender te gebruik."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"skakel tablet aan of af"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Sit foon aan of af"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Laat die program toe om die tablet aan en af te skakel."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Laat die houer toe om die opstellingsprogram wat deur die diensverskaffer voorsien word, op te roep. Behoort nooit vir gewone programme nodig te wees nie."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"luister vir waarnemings oor netwerktoestande"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Laat \'n program luister vir waarnemings oor netwerktoestande. Behoort nooit nodig te wees vir normale programme nie."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"versoek aktiveerwoord-herkenning"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Laat \'n program aktiveerwoord-herkenning versoek. Behoort nooit nodig te wees vir gewone programme nie."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 89b2dd8..32123fb 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"በጣም ብዙ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ስርዞች።"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"የጡባዊ ተኮ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"የስልክ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"አውታረ መረብ በክትትል ውስጥ ሊሆን ይችላል"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"እኔ"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"የጡባዊ አማራጮች"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"የስልክ አማራጮች"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"መተግበሪያው በዝቅተኛ ደረጃ ላይ ያሉ የWifi ማሳያዎችን እንዲቆጣጠር ይፈቅድለታል።"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"የድምጽ ውጽዓት ይቅረጹ"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"መተግበሪያው የድምጽ ውጽዓት እንዲቀርጽ እና አቅጣጫውን እንዲያዞር ያስችለዋል።"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ትኩስ ቃል ማወቅ"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"ትኩስ ቃል ለይቶ ለማወቅ ድምጽ እንዲቀርጽ ለመተግበሪያው ይፈቅድለታል። ቀረጻው በጀርባ ሊካሄድ ይችላል ነገር ግን ሌላ የድምጽ ቀረጻዎችን አይከለክልም (ለምሳሌ፣ የካሜራ መቅረጫ)።"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"የቪዲዮ ውጽዓት ይቅረጹ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"መተግበሪያው የቪዲዮ ውጽዓት እንዲቀርጽ እና አቅጣጫውን እንዲያዞር ያስችለዋል።"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ደህንነቱ የተጠበቀ የቪዲዮ ውጽዓት ይቅረጹ"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ስልክ ከማንቀላፋት ተከላከል"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ጡባዊውን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ስልኩን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ኢንፍራርድ አስተላልፍ"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"የጡባዊውን የኢንፍራሪድ አስተላላፊ እንዲጠቀም ለመተግበሪያው ይፈቅድለታል።"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"የስልኩን የኢንፍራሪድ አስተላላፊ እንዲጠቀም ለመተግበሪያው ይፈቅድለታል።"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ጡባዊ አብራ ወይም አጥፋ"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ስልክ አብራ ወይም አጥፋ"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"ጡባዊ ተኮውን ለማብራት እና ለማጥፋት ለመተግበሪያው ይፈቅዳሉ።"</string>
@@ -655,9 +665,7 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን ያዳምጣል"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"አንድ መተግበሪያ በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን እንዲያዳምጥ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አስፈላጊ ሊሆን አይገባም።"</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"የትኩስ ቃል ማወቅ ይጠይቁ"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"አንድ መተግበሪያ ትኩስ ቃል እንዲያውቅ እንዲጠይቅ ይፍቀዱለት። ለመደበኛ መተግበሪያዎች በጭራሽ አስፈላጊ ሊሆን አይገባም።"</string>
- <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ድንቦች አዘጋጅ"</string>
+ <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ማሳያውን በምትከፍትበት ጊዜ በስህተት የተተየቡ የይለፍ ቃሎችን ቁጥር ተቆጣጠር፤ እና ጡባዊ ተኮውን ቆልፍ ወይም በጣም ብዙ የተሳሳቱ የይለፍ ቃሎች ከተተየቡ የጡባዊ ተኮን ውሂብ አጥፋ፡፡"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d7f93aa..7f3e678 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"عمليات حذف <xliff:g id="CONTENT_TYPE">%s</xliff:g> كثيرة للغاية."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"سعة تخزين الجهاز اللوحي ممتلئة! احذف بعض الملفات لإخلاء مساحة."</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_managed" msgid="4030263497686867141">"بواسطة <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"أنا"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"خيارات الجهاز اللوحي"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"خيارات الهاتف"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"للسماح للتطبيق بالتحكم في الميزات ذات المستوى المنخفض في شاشات Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"التقاط إخراج الصوت"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"السماح للتطبيق بالتقاط إخراج الصوت وإعادة توجيهه."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"اكتشاف الكلمة المهمة"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"للسماح للتطبيق بالتقاط الصوت لاكتشاف الكلمة المهمة. يمكن أن يتم الالتقاط في الخلفية ولكنه لا يمنع التقاط الأصوات الأخرى (على سبيل المثال، كاميرا الفيديو)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"التقاط إخراج الفيديو"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"السماح للتطبيق بالتقاط إخراج الفيديو وإعادة توجيهه."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"التقاط إخراج الفيديو الآمن"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"منع الهاتف من الدخول في وضع السكون"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"للسماح للتطبيق بمنع الجهاز اللوحي من الانتقال إلى وضع السكون."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"للسماح للتطبيق بمنع الهاتف من الانتقال إلى وضع السكون."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"إرسال الأشعة تحت الحمراء"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"للسماح للتطبيق باستخدام مرسل الأشعة تحت الحمراء الخاص بالجهاز اللوحي."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"للسماح للتطبيق باستخدام مرسل الأشعة تحت الحمراء الخاص بالهاتف."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"تشغيل الجهاز اللوحي أو إيقاف تشغيله"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"تشغيل الهاتف أو إيقاف تشغيله"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"للسماح للتطبيق بتشغيل الجهاز اللوحي أو إيقاف تشغيله."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"للسماح للمالك باستدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"الاستماع إلى ملاحظات حول أحوال الشبكة"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"للسماح للتطبيق بالاستماع إلى ملاحظات حول أحوال الشبكة. لا حاجة إلى هذا مع التطبيقات العادية."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"طلب التعرف على الكلمة المهمة"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"للسماح للتطبيق بطلب التعرف على الكلمة المهمة. لا حاجة إلى هذا مع التطبيقات العادية."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 910853a..22464ee 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -131,6 +131,12 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Занадта шмат выдаленняў <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Памяць планшэта поўная. Выдаліце некаторыя файлы, каб вызваліць месца."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Памяць тэлефона поўная. Выдаліце некаторыя файлы, каб вызваліць месца."</string>
+ <!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Параметры планшэта"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Параметры тэлефона"</string>
@@ -490,6 +496,10 @@
<skip />
<!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
<skip />
+ <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
+ <skip />
+ <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
+ <skip />
<!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
<skip />
<!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
@@ -561,6 +571,12 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"забараняць тэлефону пераходзіць ў рэжым сну"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дазваляе прыкладанням прадухіляць пераход планшэта ў рэжым сну."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дазваляе прыкладанням прадухіляць тэлефон ад пераходу ў рэжым сну."</string>
+ <!-- no translation found for permlab_transmitIr (7545858504238530105) -->
+ <skip />
+ <!-- no translation found for permdesc_transmitIr (5358308854306529170) -->
+ <skip />
+ <!-- no translation found for permdesc_transmitIr (7957763745020300725) -->
+ <skip />
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Уключыць або выключыць планшэт"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"уключаць або выключаць тэлефон"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дазваляе прыкладанням уключаць ці адключаць планшэт."</string>
@@ -679,10 +695,6 @@
<skip />
<!-- no translation found for permdesc_accessNetworkConditions (6899102075825272211) -->
<skip />
- <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
- <skip />
- <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
- <skip />
<string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 690023c..040d274 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Изтриванията за <xliff:g id="CONTENT_TYPE">%s</xliff:g> са твърде много."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Хранилището на таблета е пълно. Изтрийте файлове, за да освободите място."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Хранилището на телефона е пълно. Изтрийте файлове, за да освободите място."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежата може да се наблюдава"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Аз"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Опции за таблета"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Опции на телефона"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Разрешава на приложението да контролира функциите от ниско ниво на дисплеите през WiFi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"записване на възпроизвеждания звук"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Разрешава на приложението да записва и пренасочва възпроизвеждания звук."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Откриване на активиращи думи"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Разрешава на приложението да записва звук с цел откриване на активиращи думи. Това може да става на заден план, но не пречи на записването на други звуци (напр. от видеокамерата)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"записване на възпроизвеждания образ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Разрешава на приложението да записва и пренасочва възпроизвеждания образ."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"записване на защитеното възпроизвеждане на образ"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"предотвратява спящ режим на телефона"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Разрешава на приложението да предотвратява преминаването на таблета в спящ режим."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Разрешава на приложението да предотвратява преминаването на телефона в спящ режим."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"предаване чрез инфрачервени лъчи"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Разрешава на приложението да използва инфрачервения предавател на таблета."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Разрешава на приложението да използва инфрачервения предавател на телефона."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"включване или изключване на таблета"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"включване или изключване на телефона"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Разрешава на приложението да включва или изключва таблета."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Разрешава на притежателя да извиква предоставеното от оператора приложение за конфигуриране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"слушане за наблюдения на мрежовите условия"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Разрешава на приложението да слуша за наблюдения на мрежовите условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"искане за разпознаване на активираща дума"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Разрешава на приложението да поиска разпознаване на активираща дума. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 31fb9c2..a58f5b2 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Massa supressions de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"L\'emmagatzematge de la tauleta és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"L\'emmagatzematge del telèfon és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Pot ser que la xarxa se supervisi."</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Mi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcions de la tauleta"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opcions del telèfon"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet a l\'aplicació controlar les funcions de baix nivell de les pantalles Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"captura la sortida d\'àudio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permet que l\'aplicació capturi i redirigeixi la sortida d\'àudio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detecció de paraules actives"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permet que l\'aplicació capturi àudio per a la detecció de paraules actives. La captura es pot produir en segon pla però no evita altres captures d\'àudio (per exemple, de càmera de vídeo)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"captura la sortida de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permet que l\'aplicació capturi i redirigeixi la sortida de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"captura la sortida de vídeo segur"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el telèfon entri en mode de repòs"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet que l\'aplicació impedeixi que la tauleta entri en repòs."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permet que l\'aplicació impedeixi que el telèfon entri en repòs."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmissió d\'infraroigs"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permet que l\'aplicació utilitzi el transmissor d\'infraroigs de la tauleta."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permet que l\'aplicació utilitzi el transmissor d\'infraroigs del telèfon."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"activa o desactiva la tauleta"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"engegar o apagar el telèfon"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permet que l\'aplicació encengui i apagui la tauleta."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet que el titular invoqui l\'aplicació de configuració proporcionada per l\'operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"conèixer les observacions sobre les condicions de la xarxa"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet que una aplicació conegui les observacions sobre les condicions de la xarxa. No s\'ha de necessitar mai per a aplicacions normals."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"sol·licitud de reconeixement de paraules actives"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Permet que una aplicació sol·liciti el reconeixement de paraules actives. No s\'ha de necessitar mai per a aplicacions normals."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Defineix les normes de contrasenya"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Control d\'intents de desbloqueig de pantalla"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 096b84e..0bd1b2f1 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Příliš mnoho smazaných položek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Úložiště tabletu je plné. Uvolněte místo smazáním některých souborů."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Paměť telefonu je plná. Uvolněte místo smazáním některých souborů."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Síť může být monitorována"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Já"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Možnosti tabletu"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Možnosti telefonu"</string>
@@ -328,7 +333,7 @@
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vynucení zavření aplikací na pozadí"</string>
<string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Umožňuje aplikaci ovládat, zda budou činnosti po přechodu na pozadí vždy ukončeny. Běžné aplikace toto oprávnění nikdy nepožadují."</string>
<string name="permlab_batteryStats" msgid="2789610673514103364">"čtení statistických údajů o baterii"</string>
- <string name="permdesc_batteryStats" msgid="5897346582882915114">"Umožňuje aplikaci číst aktuální podrobné údaje o využití baterie. Aplikace to může využít k získání podrobných informací o tom, které aplikace používáte."</string>
+ <string name="permdesc_batteryStats" msgid="5897346582882915114">"Umožňuje aplikaci číst aktuální podrobné údaje o využívání baterie. Aplikace to může využít k získání podrobných informací o tom, které aplikace používáte."</string>
<string name="permlab_updateBatteryStats" msgid="3719689764536379557">"změna statistických údajů o baterii"</string>
<string name="permdesc_updateBatteryStats" msgid="6862817857178025002">"Umožňuje aplikaci upravit shromážděné statistiky o baterii. Toto oprávnění není určeno pro běžné aplikace."</string>
<string name="permlab_getAppOpsStats" msgid="1508779687436585744">"načtení statistik operací aplikace"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Povoluje aplikaci ovládat základní funkce displejů přes Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"zachytit výstup zvuku"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Umožní aplikaci zachytit a přesměrovat výstup zvuku."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detekce klíčových slov"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Umožní aplikaci zaznamenávat zvuk za účelem detekce klíčových slov. Záznam může probíhat na pozadí a nebrání jinému zaznamenávání zvuku (například videokamerou)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"zachytit výstup videa"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Umožní aplikaci zachytit a přesměrovat výstup videa."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"zachytit zabezpečený výstup videa"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"bránění přechodu telefonu do režimu spánku"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikaci zabránit přechodu tabletu do režimu spánku."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Umožňuje aplikaci zabránit přechodu telefonu do režimu spánku."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infračervený přenos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Umožňuje aplikaci využívat infračervený vysílač tabletu."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Umožňuje aplikaci využívat infračervený vysílač telefonu."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"zapnutí či vypnutí tabletu"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"zapnutí či vypnutí telefonu"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Umožňuje aplikaci zapnout či vypnout tablet."</string>
@@ -573,7 +583,7 @@
<string name="permdesc_manageAccounts" msgid="8698295625488292506">"Umožňuje aplikaci provádět operace, jako je přidávání nebo odebírání účtů nebo mazání jejich hesel."</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"používání účtů v zařízení"</string>
<string name="permdesc_useCredentials" msgid="7984227147403346422">"Umožňuje aplikaci požadovat ověřovací tokeny."</string>
- <string name="permlab_accessNetworkState" msgid="4951027964348974773">"zobrazení síťových připojení"</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"zobrazování síťových připojení"</string>
<string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Umožňuje aplikaci zobrazit informace o síťových připojeních, například o tom, které sítě jsou k dispozici a které jsou připojené."</string>
<string name="permlab_createNetworkSockets" msgid="8018758136404323658">"úplný přístup k síti"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Umožňuje aplikaci vytvářet síťové sokety a používat vlastní síťové protokoly. K odesílání údajů na internet toto oprávnění není nutné, protože údaje lze na internet odesílat prostřednictvím prohlížečů a dalších aplikací."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje vyvolání konfigurační aplikace poskytnuté operátorem. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"naslouchat informacím o stavu sítě"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikaci naslouchat informacím o stavu sítě. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"požadavek na rozpoznání klíčových slov"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Umožňuje aplikaci požádat o rozpoznání klíčových slov. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
@@ -1584,6 +1592,6 @@
<item quantity="other" msgid="4730868920742952817">"Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Zkuste to znovu později"</string>
- <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Panel zobrazíte přejetím kraje obr."</string>
+ <string name="transient_navigation_confirmation" msgid="4907844043611123426">"Panel zobrazíte přejetím přes kraje obrazovky"</string>
<string name="transient_navigation_confirmation_long" msgid="8061685920508086697">"Systémový panel zobrazíte přejetím přes okraj obrazovky"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 50cb354..3a9da60 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange <xliff:g id="CONTENT_TYPE">%s</xliff:g> sletninger"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Din tablets lager er fuldt. Slet nogle filer for at frigøre plads."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonens lager er fuldt. Slet nogle filer for at frigøre plads."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netværket kan være overvåget"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Af en ukendt tredjepart"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Af <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Mig"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Valgmuligheder for tabletcomputeren"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonvalgmuligheder"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillader, at appen kontrollerer Wi-Fi-skærmfunktioner på lavt niveau."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"opfang et lydoutput"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Tillader, at appen opfanger og omdirigerer et lydoutput."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Registrering af kommandoord"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Tillader, at appen optager lyd til registrering af kommandoord. Optagelsen kan ske i baggrunden, men forhindrer ikke andre lydoptagelser (f.eks. videokamera)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"opfang et videooutput"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Tillader, at appen opfanger og omdirigerer et videooutput."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"opfang et sikkert videooutput"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"afholde telefonen fra at gå i dvale"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillader, at appen kan forhindre tabletten i at gå i dvale."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Tillader, at appen kan forhindre, at telefonen går i dvale."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"send infrarød"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Tillader, at appen bruger tablettens infrarøde sender."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Tillader, at appen bruger telefonens infrarøde sender."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"tænd eller sluk for tabletcomputeren"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"tænd eller sluk for telefonen"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Tillader, at appen kan slukke og tænde din tablet."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Tillader, at brugeren aktiverer konfigurationsappen, der er forsynet af mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"observer netværksforhold"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillader, at en applikation observerer netværksforhold. Bør aldrig være nødvendigt for almindelige apps."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"anmode om genkendelse af kommandoord"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Tillader, at en applikation anmoder om genkendelse af kommandoord. Bør aldrig være nødvendigt for normale apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 085a9a2..8853b37 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Der Tablet-Speicher ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Der Handyspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Das Netzwerk wird möglicherweise überwacht."</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Von einem unbekannten Dritten"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Von <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Eigene"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet-Optionen"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonoptionen"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Erlaubt der App, untergeordnete Funktionen von WLAN-Anzeigen zu steuern"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"Audioausgabe erfassen"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Ermöglicht der App die Erfassung und Weiterleitung von Audioausgaben"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword-Erkennung"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"App darf Audio für die Hotword-Erkennung erfassen. Dies kann im Hintergrund durchgeführt werden und beeinflusst die Erfassung von Audio über andere Funktionen (z. B. Camcorder) nicht."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"Videoausgabe erfassen"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Ermöglicht der App die Erfassung und Weiterleitung von Videoausgaben"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"Sichere Videoausgabe erfassen"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Ruhezustand deaktivieren"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ermöglicht der App, den Ruhezustand des Tablets zu deaktivieren"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ermöglicht der App, den Ruhezustand des Telefons zu deaktivieren"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"Infrarotübertragung"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"App darf das System zur Infrarotübertragung des Tablets verwenden."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"App darf das System zur Infrarotübertragung des Telefons verwenden."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Tablet ein- oder ausschalten"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Gerät ein- oder ausschalten"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Ermöglicht der App, das Tablet ein- oder auszuschalten"</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Inhaber, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Informationen zu den Netzwerkbedingungen erfassen"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ermöglicht der App, Informationen zu den Netzwerkbedingungen zu erfassen. Sollte für normale Apps nie benötigt werden."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"Hotword-Erkennung anfordern"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Ermöglicht einer App, eine Hotword-Erkennung anzufordern. Für normale Apps sollte dies nie erforderlich sein."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9e19261..d0cd8da 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Πάρα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγραφές."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Ο αποθηκευτικός χώρος του tablet είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</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_managed" msgid="4030263497686867141">"Από <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Για εμένα"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Επιλογές tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Επιλογές τηλεφώνου"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Επιτρέπει στην εφαρμογή τον έλεγχο των λειτουργιών χαμηλού επιπέδου των οθονών Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"έγγραφή εξόδου ήχου"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Δίνει στην εφαρμογή τη δυνατότητα εγγραφής και ανακατεύθυνσης εξόδου ήχου."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Ανίχνευση ενεργών λέξεων"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Επιτρέπει στην εφαρμογή την εγγραφή ήχου για ανίχνευση ενεργών λέξεων. Η εγγραφή μπορεί να πραγματοποιηθεί στο παρασκήνιο, αλλά δεν εμποδίζει την εγγραφή ήχου από άλλες πηγές (π.χ. βιντεοκάμερα)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"έγγραφή εξόδου βίντεο"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Δίνει στην εφαρμογή τη δυνατότητα εγγραφής και ανακατεύθυνσης εξόδου βίντεο."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"έγγραφή ασφαλούς εξόδου βίντεο"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"παρεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδράνειας"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του tablet σε κατάσταση αδράνειας."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδράνειας."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"μετάδοση υπερύθρων"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων του tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τον πομπό υπερύθρων του τηλεφώνου."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ενεργοποίηση και απενεργοποίηση tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ενεργοποίηση και απενεργοποίηση τηλεφώνου"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Επιτρέπει στην εφαρμογή να ενεργοποιήσει ή να απενεργοποιήσει το tablet."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"λήψη παρατηρήσεων σχετικά με την κατάσταση δικτύου"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Επιτρέπει σε μια εφαρμογή να λαμβάνει παρατηρήσεις σχετικά με την κατάσταση δικτύου. Δεν θα πρέπει να απαιτείται ποτέ για κανονικές εφαρμογές."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"αίτημα αναγνώρισης λέξης-κλειδιού"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Επιτρέπει σε μια εφαρμογή να υποβάλει αίτημα αναγνώρισης λέξης-κλειδιού. Δεν θα πρέπει να απαιτείται ποτέ για κανονικές εφαρμογές."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9c9b2c6..d5ed353 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"By <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet options"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Phone options"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Allows the app to control low-level features of Wi-Fi displays."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capture audio output"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Allows the app to capture and redirect audio output."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword detection"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Allows the app to capture audio for Hotword detection. The capture can happen in the background but does not prevent other audio capture (e.g. Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capture video output"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Allows the app to capture and redirect video output."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capture secure video output"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Allows the app to prevent the phone from going to sleep."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmit infrared"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Allows the app to use the tablet\'s infrared transmitter."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Allows the app to use the phone\'s infrared transmitter."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"turn tablet on or off"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"turn phone on or off"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Allows the app to turn the tablet on or off."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"request hotword recognition"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Allows an application to request hotword recognition. Should never be needed for normal apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 9c9b2c6..d5ed353 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"By <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet options"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Phone options"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Allows the app to control low-level features of Wi-Fi displays."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capture audio output"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Allows the app to capture and redirect audio output."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword detection"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Allows the app to capture audio for Hotword detection. The capture can happen in the background but does not prevent other audio capture (e.g. Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capture video output"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Allows the app to capture and redirect video output."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capture secure video output"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Allows the app to prevent the phone from going to sleep."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmit infrared"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Allows the app to use the tablet\'s infrared transmitter."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Allows the app to use the phone\'s infrared transmitter."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"turn tablet on or off"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"turn phone on or off"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Allows the app to turn the tablet on or off."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"request hotword recognition"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Allows an application to request hotword recognition. Should never be needed for normal apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 52957f8..9222e70 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento de la tablet. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del dispositivo. Elimina algunos archivos para liberar espacio."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada."</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por un tercero desconocido"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Yo"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opciones de tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opciones de dispositivo"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que la aplicación controle funciones de bajo nivel de las pantallas Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"Capturar salida de audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que la aplicación capture y redirija la salida de audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectar palabras activas"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite que la aplicación capture audio para la detección de palabras activas. La captura puede ocurrir en segundo plano, pero no impide otras capturas de audio (por ejemplo, de la videocámara)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"Capturar salida de video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite que la aplicación capture y redirija la salida de video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"Capturar salida de video segura"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el dispositivo entre en estado de inactividad"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación evite que la tablet entre en estado de inactividad."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que la aplicación evite que el dispositivo entre en estado de inactividad."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"Transmitir por infrarrojos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite que la aplicación utilice el transmisor infrarrojo de la tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite que la aplicación utilice el transmisor infrarrojo del teléfono."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"apagar o encender el tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"apagar o encender el dispositivo"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que la aplicación encienda o apague la tablet."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite al propietario ejecutar la aplicación de configuración proporcionada por el proveedor. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Detectar cambios en el estado de la red"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"solicitar reconocimiento de palabras activas"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Permite que una aplicación solicite el reconocimiento de palabras activas. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -814,7 +820,7 @@
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"Volver a intentarlo"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se superó el máximo de intentos permitido para el desbloqueo facial del dispositivo."</string>
<string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="lockscreen_charged" msgid="321635745684060624">"Cargado"</string>
+ <string name="lockscreen_charged" msgid="321635745684060624">"Cargada"</string>
<string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sin tarjeta SIM"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 2cf197b..6191dc1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento del tablet. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"De un tercero desconocido"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"De <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Yo"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opciones del tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opciones del teléfono"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que la aplicación controle funciones de bajo nivel de pantallas Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar salida de audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que la aplicación capture y redirija la salida de audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectar palabras activas"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite que la aplicación grabe audio para detectar palabras activas. La grabación se puede realizar en segundo plano pero no impide que se grabe otro tipo de audio (p.ej. la videocámara)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturar salida de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite que la aplicación capture y redirija la salida de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturar salida de vídeo segura"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el teléfono entre en modo de suspensión"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación impida que el tablet entre en modo de suspensión."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que la aplicación impida que el teléfono entre en modo de suspensión."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmitir infrarrojos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite que la aplicación utilice el transmisor de infrarrojos del tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite que la aplicación utilice el transmisor de infrarrojos del teléfono."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"encender o apagar el tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"encender o apagar el teléfono"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que la aplicación encienda o apague el tablet."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar cambios en el estado de la red"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. No debe ser necesario para aplicaciones normales."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"solicitar reconocimiento de palabras activas"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Permite que una aplicación solicite el reconocimiento de palabras activas. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
@@ -780,7 +786,7 @@
<string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Pareja de hecho"</string>
<string name="relationTypeFather" msgid="5228034687082050725">"Padre"</string>
<string name="relationTypeFriend" msgid="7313106762483391262">"Amigo/a"</string>
- <string name="relationTypeManager" msgid="6365677861610137895">"Manager"</string>
+ <string name="relationTypeManager" msgid="6365677861610137895">"Jefe"</string>
<string name="relationTypeMother" msgid="4578571352962758304">"Madre"</string>
<string name="relationTypeParent" msgid="4755635567562925226">"Padre/madre"</string>
<string name="relationTypePartner" msgid="7266490285120262781">"Pareja"</string>
@@ -814,7 +820,7 @@
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"Vuelve a intentarlo"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se ha superado el número máximo de intentos de desbloqueo facial."</string>
<string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="321635745684060624">"Cargado"</string>
+ <string name="lockscreen_charged" msgid="321635745684060624">"Cargada"</string>
<string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta el cargador"</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Falta la tarjeta SIM."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 4de52fd..8e93ec1 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liiga palju üksuse <xliff:g id="CONTENT_TYPE">%s</xliff:g> kustutusi."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tahvelarvuti mäluruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonimälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Võrku võidakse jälgida"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Tundmatu kolmas osapool:"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Domeen: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Mina"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tahvelarvuti valikud"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonivalikud"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Lubab rakendusel juhtida WiFi-ekraanide madala taseme funktsioone."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"heliväljundi jäädvustamine"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Lubab rakendusel jäädvustada ja ümber suunata heliväljundit."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Otsetee sõna tuvastamine"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Lubab rakendusel jäädvustada heli otsetee sõna tuvastamiseks. Jäädvustamine võib toimuda taustal, kuid see ei takista muud heli jäädvustamist (nt videokaameraga)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"videoväljundi jäädvustamine"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Lubab rakendusel jäädvustada ja ümber suunata videoväljundit."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"kaitstud videoväljundi jäädvustamine"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"väldi telefoni uinumist"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Võimaldab rakendusel vältida tahvelarvuti uinumist."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Võimaldab rakendusel vältida telefoni uinumist."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infrapunaedastus"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Lubab rakendusel kasutada tahvelarvuti infrapunasaatjat."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Lubab rakendusel kasutada telefoni infrapunasaatjat."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"lülita tahvelarvuti sisse või välja"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"lülita telefon sisse või välja"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Võimaldab rakendusel tahvelarvutit sisse või välja lülitada."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lubab omanikul aktiveerida operaatoripoolse konfiguratsioonirakenduse. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"võrgutingimuste teabe kuulamine"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lubab rakendusel kuulata võrgutingimuste teavet. Ei ole kunagi vajalik tavaliste rakenduste puhul."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"otsetee sõna tuvastamise taotlemine"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Lubab rakendusel taotleda otsetee sõna tuvastamist. Tavarakenduste puhul ei tohiks see vajalik olla."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 67076f5..74c904f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"تعداد موارد حذف شده <xliff:g id="CONTENT_TYPE">%s</xliff:g> بسیار زیاد است."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"حافظه رایانهٔ لوحی پر است! برخی از فایلها را حذف کنید تا فضا آزاد شود."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"حافظه تلفن پر است. بعضی از فایلها را حذف کنید تا فضا آزاد شود."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ممکن است شبکه نظارت شده باشد"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"من"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"گزینههای رایانهٔ لوحی"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"گزینههای تلفن"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"به برنامه اجازه میدهد که ویژگیهای سطح پایین صفحههای نمایش Wi‑Fi را کنترل کند."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ضبط خروجی صدا"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"به برنامه امکان میدهد خروجی صدا را ضبط و هدایت کند."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"تشخیص کلیدگفته"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"به برنامه اجازه میدهد تا صدا را برای تشخیص کلیدگفته ضبط کند. ضبط صدا میتواند در پسزمینه رخ دهد اما از ضبط صداهای دیگر (مثلاً دوربین فیلمبرداری) جلوگیری نمیکند."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ضبط خروجی ویدیو"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"به برنامه امکان میدهد خروجی ویدیو را ضبط و هدایت کند."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ضبط خروجی ویدیوی ایمن"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ممانعت از به خواب رفتن تلفن"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"به برنامه اجازه میدهد تا از غیرفعال شدن رایانهٔ لوحی جلوگیری کند."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"به برنامه اجازه میدهد تا از غیرفعال شدن تلفن جلوگیری کند."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ارسال مادون قرمز"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"به برنامه اجازه میدهد تا از فرستنده مادون قرمز رایانه لوحی استفاده کند."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"به برنامه اجازه میدهد تا از فرستنده مادون قرمز تلفن استفاده کند."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"روشن/خاموش کردن رایانهٔ لوحی"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"روشن/خاموش کردن تلفن"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"به برنامه اجازه میدهد رایانهٔ لوحی را روشن یا خاموش کند."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"به دارنده اجازه میدهد که تنظیمات برنامه شرکت مخابراتی را لغو کند. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"گوش دادن برای بررسی شرایط شبکه"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"به برنامه امکان میدهد برای بررسی شرایط شبکه گوش دهد. این امکان هرگز نباید برای برنامههای معمولی مورد نیاز باشد."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"درخواست تشخیص کلیدگفته"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"به برنامه اجازه میدهد تا تشخیص کلیدگفته را درخواست کند. هرگز برای برنامههای عادی مورد نیاز نیست."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسههای مجاز در گذرواژههای بازکردن قفل صفحه را کنترل کنید."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاشهای قفل گشایی صفحه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index b0c4254..9c05971 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liikaa <xliff:g id="CONTENT_TYPE">%s</xliff:g>-poistoja."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet-laitteen tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Puhelimen tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Verkkoa saatetaan valvoa"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Valvoja on tuntematon kolmas osapuoli."</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Valvoja on <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>."</string>
<string name="me" msgid="6545696007631404292">"Minä"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet-laitteen asetukset"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Puhelimen asetukset"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Antaa sovelluksen hallita wifi-näyttöjen matalan tason ominaisuuksia."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"äänentoiston kaappaus"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Antaa sovellukselle luvan äänentoiston kaappaamiseen ja uudelleenohjaamiseen."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Toimintosanan tunnistus"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Antaa sovelluksen siepata ääntä toimintosanojen tunnistusta varten. Sieppaus voi tapahtua taustalla, mutta se ei estä muita laitteita, kuten videokameraa, käyttämästä ääntä."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"videokuvan kaappaus"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Antaa sovellukselle luvan videokuvan kaappaamiseen ja uudelleenohjaamiseen"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"suojatun videokuvan kaappaus"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"estä puhelinta menemästä virransäästötilaan"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Antaa sovelluksen estää tablet-laitetta siirtymästä virransäästötilaan."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Antaa sovelluksen estää puhelinta siirtymästä virransäästötilaan."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infrapunalähetys"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Antaa sovelluksen käyttää tablet-laitteen infrapunalähetintä."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Antaa sovelluksen käyttää puhelimen infrapunalähetintä."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"käynnistä tai sammuta tablet-laite"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"sammutta tai käynnistä puhelin"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Antaa sovelluksen sammuttaa tai käynnistää tablet-laitteen."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Antaa luvanhaltijan käynnistää palveluntarjoajan määrityssovelluksen. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"verkon tilahavaintojen kuunteleminen"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Antaa sovellukselle luvan kuunnella verkon tilahavaintoja. Ei tavallisten sovellusten käyttöön."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"avainsanan tunnistuspyyntö"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Antaa sovelluksen pyytää avainsanan tunnistusta. Ei tavallisten sovelluksien käyttöön."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index b992d9a..832a34e 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Le réseau peut être surveillé"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Options de la tablette"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Options du téléphone"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet à l\'application de contrôler les fonctionnalités de base des écrans Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturer la sortie audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Autoriser l\'application à capturer et à rediriger la sortie audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Détection de mots clés"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permet à l\'application de capturer de l\'audio pour la détection de mots clés. La capture peut s\'effectuer en arrière-plan, et n\'empêche pas les autres opérations de capture audio (par exemple, avec un caméscope)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturer la sortie vidéo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Autoriser l\'application à capturer et à rediriger la sortie vidéo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturer la sortie vidéo sécurisée"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permet à l\'application d\'empêcher le téléphone de passer en mode veille."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmettre des signaux infrarouges"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permet à l\'application d\'utiliser l\'émetteur infrarouge de la tablette."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permet à l\'application d\'utiliser l\'émetteur infrarouge du téléphone."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"éteindre ou allumer la tablette"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"éteindre ou allumer le téléphone"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permet à l\'application d\'éteindre et d\'allumer la tablette."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par le fournisseur de services. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter les observations sur les conditions du réseau. Ne devrait jamais être nécessaire pour les applications standards."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"demander la reconnaissance des mots clés"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Permet à une application de demander la reconnaissance des mots clés. Ne devrait jamais être nécessaire pour les applications standards."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index a41cca9..563ed73 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Il est possible que le réseau soit surveillé."</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Par un tiers inconnu"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Par <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Options de la tablette"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Options du téléphone"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permet à l\'application de contrôler les fonctionnalités de base des écrans Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"enregistrer les sorties audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Autoriser l\'application à enregistrer et à rediriger les sorties audio"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Détection de mot clé"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permet à l\'application de capturer du contenu audio pour détecter des mots clés. L\'enregistrement peut se produire en arrière-plan, sans désactiver les autres services de capture audio (tels que ceux d\'un caméscope)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"enregistrer les sorties vidéo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Autoriser l\'application à enregistrer et à rediriger les sorties vidéo"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"enregistrer les sorties vidéo sécurisées"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permet à l\'application d\'empêcher le téléphone de passer en mode veille."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmettre des signaux infrarouges"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permet à l\'application d\'utiliser l\'émetteur infrarouge de la tablette."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permet à l\'application d\'utiliser l\'émetteur infrarouge du téléphone."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"éteindre ou allumer la tablette"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Éteindre ou allumer le téléphone"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permet à l\'application d\'éteindre et d\'allumer la tablette."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par l\'opérateur. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter des observations sur les conditions du réseau. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"demander la reconnaissance des mots clés"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Permet à une application de demander la reconnaissance des mots clés. Ne devrait pas être nécessaire pour les applications standards."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6d06d37..8c18c58 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"बहुत से <xliff:g id="CONTENT_TYPE">%s</xliff:g> हटाए जाते हैं."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"टेबलेट संग्रहण भर गया है. स्थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</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_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> के द्वारा"</string>
<string name="me" msgid="6545696007631404292">"मैं"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"टेबलेट विकल्प"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"फ़ोन विकल्प"</string>
@@ -202,8 +205,8 @@
<string name="permgroupdesc_camera" msgid="2933667372289567714">"चित्र या वीडियो कैप्चर के लिए कैमरे पर सीधी पहुंच."</string>
<string name="permgrouplab_screenlock" msgid="8275500173330718168">"स्क्रीन लॉक करें"</string>
<string name="permgroupdesc_screenlock" msgid="7067497128925499401">"आपके उपकरण की लॉक स्क्रीन का व्यवहार प्रभावित करने की क्षमता."</string>
- <string name="permgrouplab_appInfo" msgid="8028789762634147725">"आपके एप्लिकेशन की जानकारी"</string>
- <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"अपने उपकरण पर अन्य एप्लिकेशन के व्यवहार को प्रभावित करने की क्षमता."</string>
+ <string name="permgrouplab_appInfo" msgid="8028789762634147725">"आपके एप्स की जानकारी"</string>
+ <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"अपने उपकरण पर अन्य एप्स के व्यवहार को प्रभावित करने की क्षमता."</string>
<string name="permgrouplab_wallpaper" msgid="3850280158041175998">"वॉलपेपर"</string>
<string name="permgroupdesc_wallpaper" msgid="5630417854750540154">"उपकरण की वॉलपेपर सेटिंग बदलें."</string>
<string name="permgrouplab_systemClock" msgid="406535759236612992">"घड़ी"</string>
@@ -222,8 +225,8 @@
<string name="permgroupdesc_systemTools" msgid="8162102602190734305">"सिस्टम का निम्न-स्तर पहुंच और नियंत्रण."</string>
<string name="permgrouplab_developmentTools" msgid="3446164584710596513">"डेवलपमेंट टूल"</string>
<string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"सुविधाएं जो केवल एप्स डेवलपर के लिए आवश्यक हैं."</string>
- <string name="permgrouplab_display" msgid="4279909676036402636">"अन्य एप्लिकेशन UI"</string>
- <string name="permgroupdesc_display" msgid="6051002031933013714">"अन्य एप्लिकेशन के UI को प्रभावित करें."</string>
+ <string name="permgrouplab_display" msgid="4279909676036402636">"अन्य एप्स UI"</string>
+ <string name="permgroupdesc_display" msgid="6051002031933013714">"अन्य एप्स के UI को प्रभावित करें."</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"संग्रहण"</string>
<string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"USB संग्रहण में पहुंचें."</string>
<string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"SD कार्ड में पहुंचें."</string>
@@ -240,11 +243,11 @@
<string name="permlab_statusBar" msgid="7417192629601890791">"स्थिति बार अक्षम या बदलें"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"एप्स को स्थिति बार अक्षम करने या सिस्टम आइकन को जोड़ने या निकालने देता है."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"स्थिति बार"</string>
- <string name="permdesc_statusBarService" msgid="716113660795976060">"एप्लिकेशन को स्थिति बार होने देता है."</string>
+ <string name="permdesc_statusBarService" msgid="716113660795976060">"एप्स को स्थिति बार होने देता है."</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"स्थिति बार विस्तृत/संक्षिप्त करें"</string>
<string name="permdesc_expandStatusBar" msgid="6917549437129401132">"एप्स को स्थिति बार को विस्तृत या संक्षिप्त करने देता है."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"आउटगोइंग कॉल को कहीं और भेजें"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"एप्लिकेशन को आउटगोइंग कॉल संसाधित करने और डायल किए जाने वाला नंबर बदलने देता है. यह अनुमति एप्लिकेशन को आउटगोइंग कॉल की निगरानी करने, रीडायरेक्ट करने, या उन्हें रोकने देती है."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"एप्स को आउटगोइंग कॉल संसाधित करने और डायल किए जाने वाला नंबर बदलने देता है. यह अनुमति एप्स को आउटगोइंग कॉल की निगरानी करने, रीडायरेक्ट करने, या उन्हें रोकने देती है."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"पाठ संदेश (SMS) प्राप्त करें"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"एप्स को SMS संदेशों को प्राप्त और संसाधित करने देता है. इसका अर्थ है कि एप्स आपके उपकरण पर भेजे गए संदेशों की निगरानी आपको दिखाए बिना कर सकता है और उन्हें हटा सकता है."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"पाठ संदेश (MMS) प्राप्त करें"</string>
@@ -252,7 +255,7 @@
<string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"आपातकालीन प्रसारण प्राप्त करें"</string>
<string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"एप्स को आपातकालीन प्रसारण संदेशों को प्राप्त करने और संसाधित करने देता है. यह अनुमति केवल सिस्टम एप्स में उपलब्ध है."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"सेल प्रसारण संदेश पढ़ें"</string>
- <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"एप्लिकेशन को आपके उपकरण द्वारा प्राप्त सेल प्रसारण संदेशों को पढ़ने देता है. कुछ स्थानों पर आपको आपातकालीन स्थितियों की चेतावनी देने के लिए सेल प्रसारण अलर्ट वितरित किए जाते हैं. आपातकालीन सेल प्रसारण प्राप्त होने पर दुर्भावनापूर्ण एप्लिकेशन आपके उपकरण के निष्पादन या संचालन में हस्तक्षेप कर सकते हैं."</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"एप्स को आपके उपकरण द्वारा प्राप्त सेल प्रसारण संदेशों को पढ़ने देता है. कुछ स्थानों पर आपको आपातकालीन स्थितियों की चेतावनी देने के लिए सेल प्रसारण अलर्ट वितरित किए जाते हैं. आपातकालीन सेल प्रसारण प्राप्त होने पर दुर्भावनापूर्ण एप्स आपके उपकरण के निष्पादन या संचालन में हस्तक्षेप कर सकते हैं."</string>
<string name="permlab_sendSms" msgid="5600830612147671529">"SMS संदेश भेजें"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"एप्स को SMS संदेशों को भेजने देता है. इसके परिणामस्वरूप अप्रत्याशित शुल्क लागू हो सकते हैं. दुर्भावनापूर्ण एप्स आपकी पुष्टि के बिना संदेश भेजकर आपका धन व्यय कर सकते हैं."</string>
<string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"संदेश-द्वारा-जवाब भेजें ईवेंट"</string>
@@ -265,7 +268,7 @@
<string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"एप्स को आपके फ़ोन या सिम कार्ड में संग्रहीत SMS संदेशों को लिखने देता है. दुर्भावनापूर्ण एप्स आपके संदेशों को हटा सकते हैं."</string>
<string name="permlab_receiveWapPush" msgid="5991398711936590410">"पाठ संदेश (WAP) प्राप्त करें"</string>
<string name="permdesc_receiveWapPush" msgid="748232190220583385">"एप्स को WAP संदेशों को प्राप्त और संसाधित करने देता है. इस अनुमति में आपको भेजे गए संदेशों की निगरानी आपको दिखाए बिना करने और हटाने की क्षमता शामिल है."</string>
- <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे एप्लिकेशन पुनर्प्राप्त करें"</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"चल रहे एप्स पुनर्प्राप्त करें"</string>
<string name="permdesc_getTasks" msgid="7454215995847658102">"एप्स को वर्तमान में और हाल ही में चल रहे कार्यों के बारे में जानकारी को पुन: प्राप्त करने देता है. इससे एप्स उपकरण पर उपयोग किए गए एप्स के बारे में जानकारी खोज सकता है."</string>
<string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"उपयोगकर्ताओं के बीच सहभागिता करें"</string>
<string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"एप्स को उपकरण पर भिन्न उपयोगकर्ताओं के बीच कार्य निष्पादित करने देता है. दुर्भावनापूर्ण एप्स उपयोगकर्ताओं के बीच सुरक्षा का उल्लंघन करने के लिए इसका उपयोग कर सकते हैं."</string>
@@ -273,49 +276,49 @@
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"उपयोगकर्ताओं के बीच सभी संभव सहभागिता करने देता है."</string>
<string name="permlab_manageUsers" msgid="1676150911672282428">"उपयोगकर्ता प्रबंधित करें"</string>
<string name="permdesc_manageUsers" msgid="8409306667645355638">"एप्स को उपकरण पर क्वेरी, निर्माण और हटाने सहित उपयोगकर्ताओं को प्रबंधित करने की सुविधा देता है."</string>
- <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"चल रहे एप्लिकेशन के विवरण प्राप्त करें"</string>
+ <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"चल रहे एप्स के विवरण प्राप्त करें"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"एप्स को वर्तमान में और हाल ही में चल रहे कार्यों की जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण एप्स अन्य एप्स के बारे में निजी जानकारी खोज सकते हैं."</string>
- <string name="permlab_reorderTasks" msgid="2018575526934422779">"चल रहे एप्लिकेशन पुन: क्रमित करें"</string>
+ <string name="permlab_reorderTasks" msgid="2018575526934422779">"चल रहे एप्स पुन: क्रमित करें"</string>
<string name="permdesc_reorderTasks" msgid="7734217754877439351">"एप्स को कार्यों को अग्रभूमि और पृष्ठभूमि पर ले जाने देता है. एप्स आपके इनपुट के बिना यह कर सकता है."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्स रोकें"</string>
- <string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्लिकेशन को कार्यों को निकालने और उनके एप्लिकेशन समाप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन का व्यवहार बाधित कर सकते हैं."</string>
+ <string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्स को कार्यों को निकालने और उनके एप्स समाप्त करने देता है. दुर्भावनापूर्ण एप्स अन्य एप्स का व्यवहार बाधित कर सकते हैं."</string>
<string name="permlab_manageActivityStacks" msgid="7391191384027303065">"गतिविधि स्टैक प्रबंधित करें"</string>
<string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"एप्स को ऐसे गतिविधि स्टैक जोड़ने, निकालने, और बदलने देता है जिनमें अन्य एप्स चलते हों. दुर्भावनापूर्ण एप्स अन्य एप्स के व्यवहार में बाधा डाल सकते हैं."</string>
<string name="permlab_startAnyActivity" msgid="2918768238045206456">"कोई गतिविधि प्रारंभ करें"</string>
- <string name="permdesc_startAnyActivity" msgid="997823695343584001">"अनुमति सुरक्षा या निर्यात की स्थिति पर ध्यान दिए बिना, एप्लिकेशन को कोई गतिविधि प्रारंभ करने देता है."</string>
+ <string name="permdesc_startAnyActivity" msgid="997823695343584001">"अनुमति सुरक्षा या निर्यात की स्थिति पर ध्यान दिए बिना, एप्स को कोई गतिविधि प्रारंभ करने देता है."</string>
<string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"स्क्रीन संगतता सेट करें"</string>
- <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"एप्लिकेशन को अन्य एप्लिकेशन के स्क्रीन संगतता मोड को नियंत्रित करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन का व्यवहार बाधित कर सकते हैं."</string>
- <string name="permlab_setDebugApp" msgid="3022107198686584052">"एप्लिकेशन डीबग करना सक्षम करें"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"एप्स को अन्य एप्स के स्क्रीन संगतता मोड को नियंत्रित करने देता है. दुर्भावनापूर्ण एप्स अन्य एप्स का व्यवहार बाधित कर सकते हैं."</string>
+ <string name="permlab_setDebugApp" msgid="3022107198686584052">"एप्स डीबग करना सक्षम करें"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"एप्स को अन्य एप्स के लिए डीबग किया जाना चालू करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग अन्य एप्स को समाप्त करने के लिए कर सकते हैं."</string>
<string name="permlab_changeConfiguration" msgid="4162092185124234480">"सिस्टम प्रदर्शन सेटिंग बदलें"</string>
<string name="permdesc_changeConfiguration" msgid="4372223873154296076">"एप्स को वर्तमान कॉन्फ़िगरेशन, जैसे स्थान या समग्र अक्षरों का आकार, बदलने देता है."</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"कार मोड सक्षम करें"</string>
<string name="permdesc_enableCarMode" msgid="4853187425751419467">"एप्स को कार मोड सक्षम करने देता है."</string>
- <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"अन्य एप्लिकेशन बंद करें"</string>
- <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"एप्स को अन्य एप्लिकेशन की पृष्ठभूमि प्रक्रियाओं को समाप्त करने देता है. यह अन्य एप्स का चलना रोक सकता है."</string>
- <string name="permlab_forceStopPackages" msgid="2329627428832067700">"अन्य एप्लिकेशन बलपूर्वक बंद करें"</string>
+ <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"अन्य एप्स बंद करें"</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"एप्स को अन्य एप्स की पृष्ठभूमि प्रक्रियाओं को समाप्त करने देता है. यह अन्य एप्स का चलना रोक सकता है."</string>
+ <string name="permlab_forceStopPackages" msgid="2329627428832067700">"अन्य एप्स बलपूर्वक बंद करें"</string>
<string name="permdesc_forceStopPackages" msgid="5253157296183940812">"एप्स को अन्य एप्स बलपूर्वक बंद करने देता है."</string>
- <string name="permlab_forceBack" msgid="652935204072584616">"एप्लिकेशन को बलपूर्वक बंद करें"</string>
- <string name="permdesc_forceBack" msgid="3892295830419513623">"एप्स को अग्रभूमि में चल रही कोई भी गतिविधि बलपूर्वक बंद करने और वापस जाने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permlab_forceBack" msgid="652935204072584616">"एप्स को बलपूर्वक बंद करें"</string>
+ <string name="permdesc_forceBack" msgid="3892295830419513623">"एप्स को अग्रभूमि में चल रही कोई भी गतिविधि बलपूर्वक बंद करने और वापस जाने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_dump" msgid="1681799862438954752">"सिस्टम की आंतरिक स्थिति पुनर्प्राप्त करें"</string>
- <string name="permdesc_dump" msgid="1778299088692290329">"एप्लिकेशन को सिस्टम की आंतरिक स्थिति पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन विभिन्न प्रकार की निजी और सुरक्षा जानकारी प्राप्त कर सकते हैं जिनकी उन्हें सामान्यत: आवश्यकता नहीं होती."</string>
+ <string name="permdesc_dump" msgid="1778299088692290329">"एप्स को सिस्टम की आंतरिक स्थिति पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण एप्स विभिन्न प्रकार की निजी और सुरक्षा जानकारी प्राप्त कर सकते हैं जिनकी उन्हें सामान्यत: आवश्यकता नहीं होती."</string>
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"स्क्रीन सामग्री पुनर्प्राप्त करें"</string>
- <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"एप्लिकेशन को सक्रिय विंडो की सामग्री पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन विंडो की संपूर्ण सामग्री प्राप्त कर सकते हैं और पासवर्ड को छोड़कर इसके सभी पाठ जांच सकते हैं."</string>
+ <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"एप्स को सक्रिय विंडो की सामग्री पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण एप्स विंडो की संपूर्ण सामग्री प्राप्त कर सकते हैं और पासवर्ड को छोड़कर इसके सभी पाठ जांच सकते हैं."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"पहुंच-योग्यता को अस्थायी रूप से सक्षम करें"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"एप्स को उपकरण पर पहुंच-योग्यता को अस्थायी रूप से सक्षम करने देता है. दुर्भावनापूर्ण एप्स उपयोगकर्ता की सहमति के बिना पहुंच-योग्यता को सक्षम कर सकते हैं."</string>
<string name="permlab_retrieve_window_info" msgid="8532295199112519378">"विंडो जानकारी प्राप्त करें"</string>
- <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"एप्लिकेशन को विंडो प्रबंधक से windows के बारे में जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन आंतरिक सिस्टम उपयोग के लिए अभिप्रेत जानकारी को प्राप्त कर सकते हैं."</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"एप्स को विंडो प्रबंधक से windows के बारे में जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण एप्स आंतरिक सिस्टम उपयोग के लिए अभिप्रेत जानकारी को प्राप्त कर सकते हैं."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"ईवेंट फ़िल्टर करें"</string>
- <string name="permdesc_filter_events" msgid="8006236315888347680">"एप्लिकेशन को इनपुट फ़िल्टर पंजीकृत करने देता है, जो सभी उपयोगकर्ता ईवेंट के स्ट्रीम को भेजे जाने से पहले फ़िल्टर करता है. दुर्भावनापूर्ण एप्लिकेशन उपयोगकर्ता के हस्तक्षेप के बिना सिस्टम UI को नियंत्रित कर सकता है."</string>
+ <string name="permdesc_filter_events" msgid="8006236315888347680">"एप्स को इनपुट फ़िल्टर पंजीकृत करने देता है, जो सभी उपयोगकर्ता ईवेंट के स्ट्रीम को भेजे जाने से पहले फ़िल्टर करता है. दुर्भावनापूर्ण एप्स उपयोगकर्ता के हस्तक्षेप के बिना सिस्टम UI को नियंत्रित कर सकता है."</string>
<string name="permlab_magnify_display" msgid="5973626738170618775">"डिस्प्ले को आवर्धित करें"</string>
<string name="permdesc_magnify_display" msgid="7121235684515003792">"एप्स को डिस्प्ले की सामग्री आवर्धित करने देता है. दुर्भावनापूर्ण एप्स डिस्प्ले सामग्री को इस तरह से बदल सकते हैं कि उपकरण अनुपयोगी रेंडर होता है."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"आंशिक शटडाउन"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"गतिविधि प्रबंधक को शटडाउन स्थिति में रखता है. पूर्ण शटडाउन निष्पादित नहीं करता है."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"एप्लिकेशन स्विच करने से रोकता है"</string>
- <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"उपयोगकर्ता को दूसरे एप्लिकेशन पर स्विच करने से रोकता है."</string>
+ <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"एप्स स्विच करने से रोकता है"</string>
+ <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"उपयोगकर्ता को दूसरे एप्स पर स्विच करने से रोकता है."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"वर्तमान एप्स की जानकारी प्राप्त करें"</string>
<string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"धारक को स्क्रीन के अग्रभाग में स्थित वर्तमान एप्स के बारे में निजी जानकारी प्राप्त करने देती है."</string>
- <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"सभी एप्लिकेशन की लॉन्चिंग की निगरानी करें और उसे नियंत्रित करें"</string>
+ <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"सभी एप्स की लॉन्चिंग की निगरानी करें और उसे नियंत्रित करें"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"एप्स को यह निगरानी और नियंत्रित करने देता है कि सिस्टम कैसे गतिविधियां लॉन्च करता है. दुर्भावनापूर्ण एप्स सिस्टम को पूरी तरह से जोखिम में डाल सकते हैं. इस अनुमति की आवश्यकता केवल विकास के लिए है, सामान्य उपयोग के लिए कभी नहीं."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"पैकेज निकाले गए प्रसारण भेजें"</string>
<string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"एप्स को कोई ऐसी सूचना प्रसारित करने देता है जिसे किसी एप्स पैकेज ने निकाल दिया गया हो. दुर्भावनापूर्ण एप्स इसका उपयोग चल रहे अन्य एप्स को समाप्त करने के लिए कर सकते हैं."</string>
@@ -325,111 +328,111 @@
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"एप्स को वह सूचना प्रसारित करने देता है जो WAP PUSH संदेश को प्राप्त हुआ है. दुर्भावनापूर्ण एप्स इसका उपयोग नकली MMS संदेश प्राप्त करने या किसी वेबपृष्ठ की सामग्री को दुर्भावनापूर्ण दूसरे रूप से चुपचाप प्रतिस्थापित करने के लिए कर सकते हैं."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"चल रही प्रक्रियाओं की संख्या सीमित करें"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"एप्स को चलाई जाने वाली अधिकतम प्रक्रियाओं को नियंत्रित करने देता है. सामान्य एप्स के लिए कभी आवश्यक नहीं होती."</string>
- <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"पृष्ठभूमि एप्लिकेशन को बलपूर्वक बंद करें"</string>
+ <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"पृष्ठभूमि एप्स को बलपूर्वक बंद करें"</string>
<string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"एप्स को यह नियंत्रित करने देता है कि पृष्ठभूमि में जाते ही गतिविधियां पूर्ण हो जाती है या नही. सामान्य एप्स के लिए कभी आवश्यकता नहीं होती."</string>
<string name="permlab_batteryStats" msgid="2789610673514103364">"बैटरी के आंकड़े पढ़ें"</string>
<string name="permdesc_batteryStats" msgid="5897346582882915114">"एप्स को वर्तमान निम्न-स्तरीय बैटरी उपयोग डेटा पढ़ने देती है. एप्स को आपके द्वारा उपयोग किए जाने वाले एप्स के बारे में विस्तृत जानकारी ढूंढने दे सकती है."</string>
<string name="permlab_updateBatteryStats" msgid="3719689764536379557">"बैटरी के आंकड़े संशोधित करें"</string>
- <string name="permdesc_updateBatteryStats" msgid="6862817857178025002">"एप्लिकेशन को बैटरी के संकलित आंकड़ों को संशोधित करने देती है. सामान्य एप्लिकेशन के द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_updateBatteryStats" msgid="6862817857178025002">"एप्स को बैटरी के संकलित आंकड़ों को संशोधित करने देती है. सामान्य एप्स के द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_getAppOpsStats" msgid="1508779687436585744">"एप्स संचालन आंकड़े प्राप्त करें"</string>
<string name="permdesc_getAppOpsStats" msgid="6243887041577912877">"एप्स को संकलित एप्स संचालन आंकड़े प्राप्त करने देता है. सामान्य एप्स के द्वारा उपयोग के लिए नहीं."</string>
<string name="permlab_updateAppOpsStats" msgid="8829097373851521505">"एप्स कार्यवाही के आंकड़े बदलें"</string>
<string name="permdesc_updateAppOpsStats" msgid="50784596594403483">"एप्स को एप्स कार्यवाही के एकत्रित आंकड़े बदलने देता है. सामान्य एप्स के द्वारा उपयोग करने के लिए नहीं."</string>
- <string name="permlab_backup" msgid="470013022865453920">"सिस्टम बैकअप नियंत्रित और पुनर्स्थापित करें"</string>
- <string name="permdesc_backup" msgid="6912230525140589891">"एप्स को सिस्टम के बैकअप को नियंत्रित और क्रियाविधि को पुर्नस्थापित करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
- <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"पूर्ण बैकअप या पुनर्स्थापना कार्यवाही की पुष्टि करें"</string>
- <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"एप्लिकेशन को पूर्ण बैकअप पुष्टिकरण UI लॉन्च करने देता है. किसी एप्लिकेशन द्वारा उपयोग के लिए नहीं."</string>
+ <string name="permlab_backup" msgid="470013022865453920">"सिस्टम सुरक्षा नियंत्रित और पुनर्स्थापित करें"</string>
+ <string name="permdesc_backup" msgid="6912230525140589891">"एप्स को सिस्टम के बैकअप को नियंत्रित और क्रियाविधि को पुर्नस्थापित करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"पूर्ण सुरक्षा या पुनर्स्थापना कार्यवाही की पुष्टि करें"</string>
+ <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"एप्स को पूर्ण बैकअप पुष्टिकरण UI लॉन्च करने देता है. किसी एप्स द्वारा उपयोग के लिए नहीं."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"अनधिकृत विंडो दिखाएं"</string>
- <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"किसी एप्लिकेशन को ऐसी विंडो बनाने देता है जिनका उपयोग आंतरिक सिस्टम उपयोगकर्ता इंटरफ़ेस द्वारा किया जाना है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
- <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"अन्य एप्लिकेशन पर खींचें"</string>
+ <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"किसी एप्स को ऐसी विंडो बनाने देता है जिनका उपयोग आंतरिक सिस्टम उपयोगकर्ता इंटरफ़ेस द्वारा किया जाना है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"अन्य एप्स पर खींचें"</string>
<string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"एप्स को अन्य एप्स के शीर्ष पर या उपयोगकर्ता इंटरफ़ेस के हिस्सों पर आने देती है. वे किसी भी एप्स में इंटरफ़ेस के आपके उपयोग में हस्तक्षेप कर सकते हैं, या उस चीज को बदल सकती है जिसके बारे में आपको लगता है कि आप उसे अन्य एप्स में देख रहे हैं."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"वैश्विक एनिमेशन गति बदलें"</string>
- <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"एप्लिकेशन को किसी भी समय वैश्विक एनिमेशन गति (तेज़ या धीमे एनिमेशन) बदलने देता है."</string>
- <string name="permlab_manageAppTokens" msgid="1286505717050121370">"एप्लिकेशन टोकन प्रबंधित करें"</string>
- <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"एप्स को उनके सामान्य Z-क्रमों पर न पहुंचते हुए उनके स्वयं के टोकन बनाने और प्रबंधित करने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"एप्स को किसी भी समय वैश्विक एनिमेशन गति (तेज़ या धीमे एनिमेशन) बदलने देता है."</string>
+ <string name="permlab_manageAppTokens" msgid="1286505717050121370">"एप्स टोकन प्रबंधित करें"</string>
+ <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"एप्स को उनके सामान्य Z-क्रमों पर न पहुंचते हुए उनके स्वयं के टोकन बनाने और प्रबंधित करने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_freezeScreen" msgid="4708181184441880175">"स्क्रीन को स्थिर करें"</string>
<string name="permdesc_freezeScreen" msgid="8558923789222670064">"पूर्ण-स्क्रीन संक्रमण के लिए एप्स को अस्थायी रूप से स्क्रीन को स्थिर करने देता है."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"कुंजियों और नियंत्रण बटन को दबाएं"</string>
- <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"एप्लिकेशन को स्वयं के इनपुट ईवेंट (कुंजी दबाना, आदि) को अन्य एप्लिकेशन को वितरित करने देता है. दुर्भावनापूर्ण एप्लिकेशन टेबलेट को टेक ओवर करने में इसका उपयोग कर सकते हैं."</string>
- <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"एप्लिकेशन को स्वयं के इनपुट ईवेंट (कुंजी दबाना, आदि) अन्य एप्लिकेशन को वितरित करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग फ़ोन को टेक ओवर करने में कर सकते हैं."</string>
+ <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"एप्स को स्वयं के इनपुट ईवेंट (कुंजी दबाना, आदि) को अन्य एप्स को वितरित करने देता है. दुर्भावनापूर्ण एप्स टेबलेट को टेक ओवर करने में इसका उपयोग कर सकते हैं."</string>
+ <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"एप्स को स्वयं के इनपुट ईवेंट (कुंजी दबाना, आदि) अन्य एप्स को वितरित करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग फ़ोन को टेक ओवर करने में कर सकते हैं."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"आप जो भी लिखते हैं और जो कार्यवाहियां करते हैं उन्हें रिकॉर्ड करें"</string>
- <string name="permdesc_readInputState" msgid="8387754901688728043">"एप्स को अन्य एप्स के साथ सहभागिता करते समय भी आपके द्वारा दबाई जाने वाली कुंजियां देखने देता है (जैसे कोई पासवर्ड लिखना). सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_readInputState" msgid="8387754901688728043">"एप्स को अन्य एप्स के साथ सहभागिता करते समय भी आपके द्वारा दबाई जाने वाली कुंजियां देखने देता है (जैसे कोई पासवर्ड लिखना). सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"किसी इनपुट विधि से आबद्ध करें"</string>
- <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"धारक को किसी इनपुट विधि के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"धारक को किसी इनपुट विधि के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"पहुंच-योग्यता सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"धारक को किसी पहुंच-योग्यता सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"धारक को किसी पहुंच-योग्यता सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindPrintService" msgid="8462815179572748761">"प्रिंट सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindPrintService" msgid="7960067623209111135">"धारक को किसी प्रिंट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindPrintService" msgid="7960067623209111135">"धारक को किसी प्रिंट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindPrintSpoolerService" msgid="6807762783744125954">"प्रिंट स्पूलर सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindPrintSpoolerService" msgid="3680552285933318372">"धारक को प्रिंट स्पूलर सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindPrintSpoolerService" msgid="3680552285933318372">"धारक को प्रिंट स्पूलर सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindNfcService" msgid="2752731300419410724">"NFC सेवा से आबद्ध रहें"</string>
<string name="permdesc_bindNfcService" msgid="6120647629174066862">"धारक को ऐसे एप्स से आबद्ध रहने देता है जो NFC कार्ड का अनुकरण कर रहे हैं. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindTextService" msgid="7358378401915287938">"किसी पाठ सेवा पर बने रहें"</string>
- <string name="permdesc_bindTextService" msgid="8151968910973998670">"धारक को किसी पाठ सेवा (उदा. SpellCheckerService) के शीर्ष-स्तर इंटरफ़ेस पर आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindTextService" msgid="8151968910973998670">"धारक को किसी पाठ सेवा (उदा. SpellCheckerService) के शीर्ष-स्तर इंटरफ़ेस पर आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"किसी VPN सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"वॉलपेपर से आबद्ध करें"</string>
- <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string>
- <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्यवस्थापक के साथ सहभागिता करें"</string>
- <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्यवस्थापक को उद्देश्य भेजने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्यवस्थापक को उद्देश्य भेजने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण उपकरण सुचारू ढ़ंग से चलाने वाले को जोड़ें या निकालें"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"धारक को सक्रिय डिवाइस व्यवस्थापकों को जोड़ने या निकालने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"स्क्रीन अभिविन्यास बदलें"</string>
- <string name="permdesc_setOrientation" msgid="3046126619316671476">"एप्लिकेशन को किसी भी समय स्क्रीन का रोटेशन बदलने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_setOrientation" msgid="3046126619316671476">"एप्स को किसी भी समय स्क्रीन का रोटेशन बदलने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"सूचक गति बदलें"</string>
- <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"एप्स को माउस या ट्रैकपैड सूचक गति को किसी भी समय बदलने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"एप्स को माउस या ट्रैकपैड सूचक गति को किसी भी समय बदलने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"कीबोर्ड लेआउट बदलें"</string>
- <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"एप्लिकेशन को कीबोर्ड लेआउट बदलने देता है. सामान्य एप्लिकेशन के लिए कभी आवश्यक नहीं है."</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"एप्स को कीबोर्ड लेआउट बदलने देता है. सामान्य एप्स के लिए कभी आवश्यक नहीं है."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"एप्स को Linux सिग्नल भेजें"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"एप्लिकेशन को यह अनुरोध करने देता है कि दिया गया सिग्नल सभी जारी प्रक्रियाओं को भेजा जाए."</string>
- <string name="permlab_persistentActivity" msgid="8841113627955563938">"एप्लिकेशन को हमेशा चलने वाला बनाएं"</string>
- <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"एप्लिकेशन को स्मृति में स्वयं के कुछ हिस्सों को लगातार बनाने की अनुमति देता है. यह अन्य एप्स के लिए उपलब्ध स्मृति को सीमित कर टेबलेट को धीमा कर सकता है."</string>
- <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"एप्लिकेशन को स्मृति में स्वयं के कुछ हिस्सों को लगातार बनाने देता है. यह अन्य एप्स के लिए उपलब्ध स्मृति को सीमित कर फ़ोन को धीमा कर सकता है."</string>
- <string name="permlab_deletePackages" msgid="184385129537705938">"एप्लिकेशन हटाएं"</string>
+ <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"एप्स को यह अनुरोध करने देता है कि दिया गया सिग्नल सभी जारी प्रक्रियाओं को भेजा जाए."</string>
+ <string name="permlab_persistentActivity" msgid="8841113627955563938">"एप्स को हमेशा चलने वाला बनाएं"</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"एप्स को स्मृति में स्वयं के कुछ हिस्सों को लगातार बनाने की अनुमति देता है. यह अन्य एप्स के लिए उपलब्ध स्मृति को सीमित कर टेबलेट को धीमा कर सकता है."</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"एप्स को स्मृति में स्वयं के कुछ हिस्सों को लगातार बनाने देता है. यह अन्य एप्स के लिए उपलब्ध स्मृति को सीमित कर फ़ोन को धीमा कर सकता है."</string>
+ <string name="permlab_deletePackages" msgid="184385129537705938">"एप्स हटाएं"</string>
<string name="permdesc_deletePackages" msgid="7411480275167205081">"एप्स को Android पैकेज हटाने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग महत्वपूर्ण एप्स हटाने के लिए कर सकते हैं."</string>
- <string name="permlab_clearAppUserData" msgid="274109191845842756">"अन्य एप्लिकेशन का डेटा हटाएं"</string>
+ <string name="permlab_clearAppUserData" msgid="274109191845842756">"अन्य एप्स का डेटा हटाएं"</string>
<string name="permdesc_clearAppUserData" msgid="4625323684125459488">"एप्स को उपयोगकर्ता डेटा साफ़ करने देता है."</string>
- <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"अन्य एप्लिकेशन के संचय हटाएं"</string>
+ <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"अन्य एप्स के संचय हटाएं"</string>
<string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"एप्स को संचय फ़ाइलें हटाने देता है."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"एप्स संग्रहण स्थान मापें"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"एप्स को उसका कोड, डेटा, और संचय आकारों को प्राप्त करने देता है"</string>
- <string name="permlab_installPackages" msgid="2199128482820306924">"सीधे एप्लिकेशन इंस्टॉल करें"</string>
- <string name="permdesc_installPackages" msgid="5628530972548071284">"एप्स को नए या अपडेट किए गए Android पैकेज इंस्टॉल करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग अनियंत्रित रूप से सशक्त अनुमतियों वाले नए एप्स जोड़ने में कर सकते हैं."</string>
+ <string name="permlab_installPackages" msgid="2199128482820306924">"सीधे एप्स इंस्टॉल करें"</string>
+ <string name="permdesc_installPackages" msgid="5628530972548071284">"एप को नए या नई जानकारी वाले Android पैकेज इंस्टॉल करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग अनियंत्रित रूप से सशक्त अनुमतियों वाले नए एप्स जोड़ने में कर सकते हैं."</string>
<string name="permlab_clearAppCache" msgid="7487279391723526815">"सभी एप्स संचय डेटा हटाएं"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"एप्स को अन्य एप्स की संचय निर्देशिकाओं में से फ़ाइलें हटाकर टेबलेट संग्रहण को खाली करने देती है. इससे अन्य एप्स अधिक धीमे प्रारंभ हो सकते हैं क्योंकि उन्हें अपना डेटा पुनर्प्राप्त करने की आवश्यकता होती है."</string>
<string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"एप्स को अन्य एप्स की संचय निर्देशिकाओं में से फ़ाइलें हटाकर फ़ोन संग्रहण को खाली करने देती है. इससे अन्य एप्स अधिक धीमे प्रारंभ हो सकते हैं क्योंकि उन्हें अपना डेटा पुनर्प्राप्त करने की आवश्यकता होती है."</string>
- <string name="permlab_movePackage" msgid="3289890271645921411">"एप्लिकेशन संसाधनों को ले जाएं"</string>
- <string name="permdesc_movePackage" msgid="319562217778244524">"एप्लिकेशन को एप्लिकेशन संसाधनों को आंतरिक से बाहरी मीडिया में और इसके विपरीत ले जाने देता है."</string>
+ <string name="permlab_movePackage" msgid="3289890271645921411">"एप्स संसाधनों को ले जाएं"</string>
+ <string name="permdesc_movePackage" msgid="319562217778244524">"एप्स को एप्स संसाधनों को आंतरिक से बाहरी मीडिया में और इसके विपरीत ले जाने देता है."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"संवेदनशील लॉग डेटा पढ़ें"</string>
- <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"किसी एप्लिकेशन को सिस्टम की विभिन्न लॉग फ़ाइलों से पढ़ने देता है. संभावित रूप से व्यक्तिगत या निजी जानकारी शामिल करते हुए, टेबलेट के साथ आप क्या कर रहे हैं इस बारे में सामान्य जानकारी खोजने देता है."</string>
- <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"एप्लिकेशन को सिस्टम की विभिन्न लॉग फ़ाइलें पढ़ने देता है. संभावित रूप से व्यक्तिगत या निजी जानकारी सहित, यह इसे इस बारे में सामान्य जानकारी खोजने देता है कि आप फ़ोन से क्या कर रहे हैं."</string>
+ <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"किसी एप्स को सिस्टम की विभिन्न लॉग फ़ाइलों से पढ़ने देता है. संभावित रूप से व्यक्तिगत या निजी जानकारी शामिल करते हुए, टेबलेट के साथ आप क्या कर रहे हैं इस बारे में सामान्य जानकारी खोजने देता है."</string>
+ <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"एप्स को सिस्टम की विभिन्न लॉग फ़ाइलें पढ़ने देता है. संभावित रूप से व्यक्तिगत या निजी जानकारी सहित, यह इसे इस बारे में सामान्य जानकारी खोजने देता है कि आप फ़ोन से क्या कर रहे हैं."</string>
<string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"प्लेबैक के लिए किसी भी मीडिया डीकोडर का उपयोग करें"</string>
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"एप्स को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"विश्वसनीय क्रेडेंशियल प्रबंधित करें"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"एप्स को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"निदान के स्वामित्व वाले संसाधनों को पढ़ें/लिखें"</string>
- <string name="permdesc_diagnostic" msgid="6608295692002452283">"एप्लिकेशन को diag समूह के स्वामित्व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्टम की स्थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
- <string name="permlab_changeComponentState" msgid="6335576775711095931">"एप्लिकेशन घटकों को सक्षम या अक्षम करें"</string>
- <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"एप्लिकेशन को यह बदलने देता है कि किसी अन्य एप्लिकेशन का घटक सक्षम है या नहीं. दुर्भावनापूर्ण एप्लिकेशन महत्वपूर्ण फ़ोन क्षमताओं को अक्षम करने में इसका उपयोग कर सकते हैं. इस अनुमति का उपयोग सावधानी के साथ करना चाहिए, क्योंकि इससे एप्लिकेशन घटकों के अनुपयोगी, असंगत, या अस्थिर स्थिति में जाने की संभावना है."</string>
- <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"एप्लिकेशन को यह बदलने देता है कि किसी अन्य एप्लिकेशन का घटक सक्षम है या नहीं. दुर्भावनापूर्ण एप्लिकेशन महत्वपूर्ण फ़ोन क्षमताओं को अक्षम करने में इसका उपयोग कर सकते हैं. इस अनुमति का उपयोग सावधानी के साथ करना चाहिए, क्योंकि इससे एप्लिकेशन घटकों के अनुपयोगी, असंगत, या अस्थिर स्थिति में जाने की संभावना है."</string>
+ <string name="permdesc_diagnostic" msgid="6608295692002452283">"एप्स को diag समूह के स्वामित्व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्टम की स्थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
+ <string name="permlab_changeComponentState" msgid="6335576775711095931">"एप्स घटकों को सक्षम या अक्षम करें"</string>
+ <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"एप्स को यह बदलने देता है कि किसी अन्य एप्स का घटक सक्षम है या नहीं. दुर्भावनापूर्ण एप्स महत्वपूर्ण फ़ोन क्षमताओं को अक्षम करने में इसका उपयोग कर सकते हैं. इस अनुमति का उपयोग सावधानी के साथ करना चाहिए, क्योंकि इससे एप्स घटकों के अनुपयोगी, असंगत, या अस्थिर स्थिति में जाने की संभावना है."</string>
+ <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"एप्स को यह बदलने देता है कि किसी अन्य एप्स का घटक सक्षम है या नहीं. दुर्भावनापूर्ण एप्स महत्वपूर्ण फ़ोन क्षमताओं को अक्षम करने में इसका उपयोग कर सकते हैं. इस अनुमति का उपयोग सावधानी के साथ करना चाहिए, क्योंकि इससे एप्स घटकों के अनुपयोगी, असंगत, या अस्थिर स्थिति में जाने की संभावना है."</string>
<string name="permlab_grantRevokePermissions" msgid="4627315351093508795">"अनुमति दें या रद्द करें"</string>
<string name="permdesc_grantRevokePermissions" msgid="4088642654085850662">"एप्स को उसके या अन्य एप्स के लिए विशेष अनुमतियां देने या रद्द करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग उन सुविधाओं तक पहुंचने के लिए कर सकते हैं जो आपने उन्हें नहीं दी हैं."</string>
- <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"पसंदीदा एप्लिकेशन सेट करें"</string>
+ <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"पसंदीदा एप्स सेट करें"</string>
<string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"एप्स को आपके पसंदीदा एप्स को संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपसे निजी डेटा एकत्रित करने के लिए आपके मौजूदा एप्स को स्पूफ़ करके, चलाए जाने वाले एप्स को चुपचाप बदल सकते हैं."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"सिस्टम सेटिंग बदलें"</string>
<string name="permdesc_writeSettings" msgid="7775723441558907181">"एप्स को सिस्टम सेटिंग डेटा संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपके सिस्टम के कॉन्फ़िगरेशन को दूषित कर सकते हैं."</string>
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"सुरक्षित सिस्टम सेटिंग बदलें"</string>
- <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"एप्स को सिस्टम के सुरक्षित सेटिंग डेटा को संशोधित करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Google सेवाएं मैप बदलें"</string>
- <string name="permdesc_writeGservices" msgid="1287309437638380229">"एप्लिकेशन को Google सेवाओं का मानचित्र संशोधित करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"एप्स को सिस्टम के सुरक्षित सेटिंग डेटा को संशोधित करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_writeGservices" msgid="2149426664226152185">"Google सेवाएं नक्शा बदलें"</string>
+ <string name="permdesc_writeGservices" msgid="1287309437638380229">"एप्स को Google सेवाओं का नक्शे संशोधित करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"प्रारंभ होने पर चलाएं"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"एप्स को सिस्टम द्वारा बूटिंग पूर्ण करते ही स्वतः आरंभ करने देता है. इससे टेबलेट को आरंभ होने में अधिक समय लग सकता है और एप्स को निरंतर चलाकर संपूर्ण टेबलेट को धीमा करने देता है."</string>
<string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"एप्स को सिस्टम द्वारा बूटिंग पूर्ण करते ही स्वतः प्रारंभ होने देता है. इससे फ़ोन को प्रारंभ होने में अधिक समय लग सकता है और एप्स के निरंतर चलते रहने से संपूर्ण फ़ोन प्रक्रियाएं धीमी हो सकती हैं."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"स्टिकी प्रसारण भेजें"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"एप्लिकेशन को स्टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, टेबलेट की बहुत अधिक स्मृति का उपयोग करके उसे धीमा या अस्थिर कर सकता है."</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"एप्लिकेशन को स्टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, फ़ोन की बहुत अधिक स्मृति का उपयोग करके उसे धीमा या अस्थिर कर सकता है."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"एप्स को स्टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, टेबलेट की बहुत अधिक स्मृति का उपयोग करके उसे धीमा या अस्थिर कर सकता है."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"एप्स को स्टिकी प्रसारण भेजने देता है, जो प्रसारण समाप्त होने के बाद भी बने रहते हैं. अत्यधिक उपयोग, फ़ोन की बहुत अधिक स्मृति का उपयोग करके उसे धीमा या अस्थिर कर सकता है."</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"अपने संपर्क पढ़ें"</string>
<string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"एप्स को आपके टेबलेट में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को पढ़ने देता है. यह अनुमति एप्स को आपके संपर्क डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्स आपकी जानकारी के बिना संपर्क डेटा को साझा कर सकते हैं."</string>
<string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"एप्स को आपके फ़ोन में संग्रहीत संपर्कों के डेटा को, साथ ही आपके द्वारा विशिष्ट व्यक्तियों को कॉल करने, ईमेल करने, या अन्य तरीके से संवाद करने की आवृत्ति को पढ़ने देता है. यह अनुमति एप्स को आपके संपर्क डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्स आपकी जानकारी के बिना संपर्क डेटा को साझा कर सकते हैं."</string>
@@ -440,16 +443,16 @@
<string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"एप्स को आपके फ़ोन का कॉल लॉग पढ़ने देता है, जिसमें इनकमिंग और आउटगोइंग कॉल का डेटा शामिल है. यह अनुमति एप्स को आपके कॉल लॉग डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्स आपकी जानकारी के बिना कॉल लॉग डेटा को साझा कर सकते हैं."</string>
<string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"एप्स को आपके फ़ोन का कॉल लॉग पढ़ने देता है, जिसमें इनकमिंग और आउटगोइंग कॉल का डेटा शामिल है. यह अनुमति एप्स को आपके कॉल लॉग डेटा को सहेजने देती है, और दुर्भावनापूर्ण एप्स आपकी जानकारी के बिना कॉल लॉग डेटा को साझा कर सकते हैं."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"कॉल लॉग लिखें"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"एप्लिकेशन को इनकमिंग और आउटगोइंग कॉल के डेटा सहित, आपके टेबलेट का कॉल लॉग संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके कॉल लॉग को मिटाने या संशोधित करने के लिए इसका उपयोग कर सकते हैं."</string>
- <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"एप्लिकेशन को इनकमिंग और आउटगोइंग कॉल के डेटा सहित, आपके फ़ोन का कॉल लॉग संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके कॉल लॉग को मिटाने या संशोधित करने के लिए इसका उपयोग कर सकते हैं."</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"एप्स को इनकमिंग और आउटगोइंग कॉल के डेटा सहित, आपके टेबलेट का कॉल लॉग संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपके कॉल लॉग को मिटाने या संशोधित करने के लिए इसका उपयोग कर सकते हैं."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"एप्स को इनकमिंग और आउटगोइंग कॉल के डेटा सहित, आपके फ़ोन का कॉल लॉग संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपके कॉल लॉग को मिटाने या संशोधित करने के लिए इसका उपयोग कर सकते हैं."</string>
<string name="permlab_readProfile" msgid="4701889852612716678">"स्वयं का संपर्क कार्ड पढ़ें"</string>
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"एप्स को आपके उपकरण में संग्रहीत व्यक्तिगत प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी, पढ़ने देता है. इसका अर्थ है कि एप्स आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"स्वयं का संपर्क कार्ड बदलें"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"एप्स को आपके उपकरण में संग्रहीत निजी प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी को बदलने या उसमें कुछ जोड़ने देता है. इसका अर्थ है कि एप्स आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"अपनी सामाजिक स्ट्रीम पढ़ें"</string>
- <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"एप्स को आपके और आपके मित्रों के सामाजिक अपडेट तक पहुंचने और उन्हें समन्वयित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे गोपनीयता पर ध्यान दिए बिना, एप्स सामाजिक नेटवर्क पर आपके और आपके मित्रों के बीच संचारों को पढ़ सकता है. ध्यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
+ <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"एप को आपके और आपके मित्रों की नई सामाजिक जानकारी तक पहुंचने और उन्हें समन्वयित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे गोपनीयता पर ध्यान दिए बिना, एप सामाजिक नेटवर्क पर आपके और आपके मित्रों के बीच संचारों को पढ़ सकता है. ध्यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"सामाजिक स्ट्रीम में लिखें"</string>
- <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"एप्स को आपके मित्रों के सामाजिक अपडेट प्रदर्शित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे एप्स ऐसे संदेश बना सकता है जो किसी मित्र की ओर से आते दिखाई देते हैं. ध्यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
+ <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"एप को आपके मित्रों की नई सामाजिक जानकारी प्रदर्शित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे एप्स ऐसे संदेश बना सकता है जो किसी मित्र की ओर से आते दिखाई देते हैं. ध्यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"केलैंडर ईवेंट के साथ-साथ गोपनीय जानकारी पढ़ें"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"एप्स को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके टेबलेट पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, एप्स आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
<string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"एप्स को मित्रों या सहकर्मियों के कैलेंडर इवेंट सहित, आपके फ़ोन पर संग्रहीत कैलेंडर इवेंट पढ़ने देता है. इससे गोपनीयता या संवेदनशीलता पर ध्यान दिए बिना, एप्स आपके कैलेंडर डेटा को साझा कर सकता है या सहेज सकता है."</string>
@@ -467,19 +470,21 @@
<string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"अनुमानित स्थान (नेटवर्क-आधारित)"</string>
<string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"एप्स को आपका अनुमानित स्थान प्राप्त करने देती है. इस स्थान को सेल टॉवर और Wi-Fi जैसे नेटवर्क स्थान स्रोतों का उपयोग करके स्थान सेवाओं द्वारा प्राप्त किया गया है. एप्स द्वारा इन स्थान सेवाओं का उपयोग करने के लिए इन्हें चालू होना चाहिए और आपके उपकरण में उपलब्ध होना चाहिए. एप्स इसका उपयोग यह पता लगाने में कर सकते हैं कि आप लगभग कहां पर हैं."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlinger में पहुंचें"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"एप्लिकेशन को SurfaceFlinger निम्न-स्तर सुविधाएं उपयोग करने देता है."</string>
+ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"एप्स को SurfaceFlinger निम्न-स्तर सुविधाएं उपयोग करने देता है."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"फ़्रेम बफ़र पढ़ें"</string>
- <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"एप्लिकेशन को फ़्रेम बफ़र की सामग्री पढ़ने देता है."</string>
+ <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"एप्स को फ़्रेम बफ़र की सामग्री पढ़ने देता है."</string>
<string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wifi डिस्प्ले को कॉन्फ़िगर करें"</string>
<string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"एप्स को कॉन्फ़िगर करने देता है और Wifi डिस्प्ले से कनेक्ट करता है."</string>
<string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi डिस्प्ले को नियंत्रित करें"</string>
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"एप्स को Wifi डिस्प्ले की निम्न-स्तर की सुविधाएं नियंत्रित करने देता है."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ऑडियो आउटपुट को कैप्चर करें"</string>
- <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"एप्लिकेशन को ऑडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
+ <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"एप्स को ऑडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"हॉटवर्ड पहचान"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"एप्लिकेशन को हॉटवर्ड पहचान के लिए ऑडियो कैप्चर करने देती है. कैप्चर पृष्ठभूमि में हो सकता है लेकिन वह अन्य ऑडियो कैप्चर (उदा. कैमकॉर्डर) को नहीं रोकता."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"वीडियो आउटपुट को कैप्चर करें"</string>
- <string name="permdesc_captureVideoOutput" msgid="359481658034149860">"एप्लिकेशन को वीडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
+ <string name="permdesc_captureVideoOutput" msgid="359481658034149860">"एप्स को वीडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"सुरक्षित वीडियो आउटपुट को कैप्चर करें"</string>
- <string name="permdesc_captureSecureVideoOutput" msgid="2779793064709350289">"एप्लिकेशन को सुरक्षित वीडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
+ <string name="permdesc_captureSecureVideoOutput" msgid="2779793064709350289">"एप्स को सुरक्षित वीडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"अपनी ऑडियो सेटिंग बदलें"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"एप्स को वैश्विक ऑडियो सेटिंग, जैसे वॉल्यूम और कौन-सा स्पीकर आउटपुट के लिए उपयोग किया गया, संशोधित करने देता है."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"ऑडियो रिकॉर्ड करें"</string>
@@ -490,87 +495,90 @@
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"पहले से इंस्टॉल किए गए सिस्टम एप्स को कैमरे को संकेतक LED का उपयोग करने से अक्षम करती है."</string>
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"स्थायी रूप से टेबलेट अक्षम करें"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"फ़ोन को स्थायी रूप से अक्षम करें"</string>
- <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"एप्लिकेशन को संपूर्ण टेबलेट को स्थायी रूप से अक्षम करने देता है. यह बहुत खतरनाक है."</string>
- <string name="permdesc_brick" product="default" msgid="5788903297627283099">"एप्लिकेशन को संपूर्ण फ़ोन को स्थायी रूप से अक्षम करने देता है. यह बहुत खतरनाक है."</string>
+ <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"एप्स को संपूर्ण टेबलेट को स्थायी रूप से अक्षम करने देता है. यह बहुत खतरनाक है."</string>
+ <string name="permdesc_brick" product="default" msgid="5788903297627283099">"एप्स को संपूर्ण फ़ोन को स्थायी रूप से अक्षम करने देता है. यह बहुत खतरनाक है."</string>
<string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"टेबलेट रीबूट के लिए बाध्य करें"</string>
<string name="permlab_reboot" product="default" msgid="2898560872462638242">"फ़ोन रीबूट के लिए बाध्य करें"</string>
- <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"एप्लिकेशन को टेबलेट रीबूट करने के लिए बाध्य करने देता है."</string>
- <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"एप्लिकेशन को फ़ोन बलपूर्वक रीबूट करने देता है."</string>
+ <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"एप्स को टेबलेट रीबूट करने के लिए बाध्य करने देता है."</string>
+ <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"एप्स को फ़ोन बलपूर्वक रीबूट करने देता है."</string>
<string name="permlab_mount_unmount_filesystems" product="nosdcard" msgid="2927361537942591841">"USB संग्रहण फ़ाइल सिस्टम पर पहुंचें"</string>
<string name="permlab_mount_unmount_filesystems" product="default" msgid="4402305049890953810">"SD कार्ड फ़ाइल सिस्टम पर पहुंचें"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"एप्लिकेशन को निकाले जाने योग्य संग्रहण के लिए फ़ाइल सिस्टम माउंट और अनमाउंट करने देता है."</string>
+ <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"एप्स को निकाले जाने योग्य संग्रहण के लिए फ़ाइल सिस्टम माउंट और अनमाउंट करने देता है."</string>
<string name="permlab_mount_format_filesystems" product="nosdcard" msgid="6227819582624904972">"USB संग्रहण मिटाएं"</string>
<string name="permlab_mount_format_filesystems" product="default" msgid="262582698639274056">"SD कार्ड मिटाएं"</string>
- <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"एप्लिकेशन को निकालने योग्य संग्रहण फ़ॉर्मेट करने देता है."</string>
+ <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"एप्स को निकालने योग्य संग्रहण फ़ॉर्मेट करने देता है."</string>
<string name="permlab_asec_access" msgid="3411338632002193846">"मोबाइल संग्रहण पर जानकारी प्राप्त करें"</string>
<string name="permdesc_asec_access" msgid="3094563844593878548">"एप्स को मोबाइल संग्रहण की जानकारी प्राप्त करने देता है."</string>
<string name="permlab_asec_create" msgid="6414757234789336327">"मोबाइल संग्रहण बनाएं"</string>
- <string name="permdesc_asec_create" msgid="4558869273585856876">"एप्लिकेशन को मोबाइल संग्रहण बनाने देता है."</string>
+ <string name="permdesc_asec_create" msgid="4558869273585856876">"एप्स को मोबाइल संग्रहण बनाने देता है."</string>
<string name="permlab_asec_destroy" msgid="526928328301618022">"मोबाइल संग्रहण नष्ट करें"</string>
- <string name="permdesc_asec_destroy" msgid="7218749286145526537">"एप्लिकेशन को मोबाइल संग्रहण नष्ट करने देता है."</string>
+ <string name="permdesc_asec_destroy" msgid="7218749286145526537">"एप्स को मोबाइल संग्रहण नष्ट करने देता है."</string>
<string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"मोबाइल संग्रहण माउंट/अनमाउंट करें"</string>
- <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"एप्लिकेशन को मोबाइल संग्रहण माउंट/अनमाउंट करने देता है."</string>
+ <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"एप्स को मोबाइल संग्रहण माउंट/अनमाउंट करने देता है."</string>
<string name="permlab_asec_rename" msgid="7496633954080472417">"मोबाइल संग्रहण का नाम बदलें"</string>
- <string name="permdesc_asec_rename" msgid="1794757588472127675">"एप्लिकेशन को मोबाइल संग्रहण का नाम बदलने देता है."</string>
+ <string name="permdesc_asec_rename" msgid="1794757588472127675">"एप्स को मोबाइल संग्रहण का नाम बदलने देता है."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करें"</string>
- <string name="permdesc_vibrate" msgid="6284989245902300945">"एप्लिकेशन को कंपनकर्ता नियंत्रित करने देता है."</string>
+ <string name="permdesc_vibrate" msgid="6284989245902300945">"एप्स को कंपनकर्ता नियंत्रित करने देता है."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"फ़्लैशलाइट नियंत्रित करें"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"एप्लिकेशन को फ़्लैशलाइट नियंत्रित करने देता है."</string>
+ <string name="permdesc_flashlight" msgid="6522284794568368310">"एप्स को फ़्लैशलाइट नियंत्रित करने देता है."</string>
<string name="permlab_manageUsb" msgid="1113453430645402723">"USB उपकरणों की प्राथमिकताएं और अनुमतियां प्रबंधित करें"</string>
- <string name="permdesc_manageUsb" msgid="7776155430218239833">"एप्लिकेशन को USB उपकरणों की प्राथमिकताओं और अनुमतियों को प्रबंधित करने देता है."</string>
+ <string name="permdesc_manageUsb" msgid="7776155430218239833">"एप्स को USB उपकरणों की प्राथमिकताओं और अनुमतियों को प्रबंधित करने देता है."</string>
<string name="permlab_accessMtp" msgid="4953468676795917042">"MTP प्रोटोकॉल लागू करें"</string>
<string name="permdesc_accessMtp" msgid="6532961200486791570">"MTP USB प्रोटोकॉल लागू करने के लिए कर्नेल MTP ड्राइवर में पहुंच की अनुमति देता है."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"परीक्षण हार्डवेयर"</string>
- <string name="permdesc_hardware_test" msgid="6597964191208016605">"एप्लिकेशन को हार्डवेयर परीक्षण के लिए विविध सहायक उपकरणों को नियंत्रित करने देता है."</string>
+ <string name="permdesc_hardware_test" msgid="6597964191208016605">"एप्स को हार्डवेयर परीक्षण के लिए विविध सहायक उपकरणों को नियंत्रित करने देता है."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"फ़ोन नंबर पर सीधे कॉल करें"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"एप्स को आपके हस्तक्षेप के बिना फ़ोन नंबर पर कॉल करने देता है. इसके परिणाम अप्रत्याशित शुल्क या कॉल हो सकते हैं. ध्यान दें कि यह एप्स को आपातकालीन नंबर पर कॉल नहीं करने देता. दुर्भावनापूर्ण एप्स आपकी पुष्टि के बिना कॉल करके आपका धन व्यय कर सकते हैं."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"किसी भी फ़ोन नंबर पर सीधे कॉल करें"</string>
- <string name="permdesc_callPrivileged" msgid="1689024901509996810">"एप्लिकेशन को आपके हस्तक्षेप के बिना आपातकालीन नंबरों सहित, किसी भी फ़ोन नंबर पर कॉल करने देता है. दुर्भावनापूर्ण एप्लिकेशन आपातकालीन सेवाओं पर अनावश्यक और अवैध कॉल कर सकते हैं."</string>
+ <string name="permdesc_callPrivileged" msgid="1689024901509996810">"एप्स को आपके हस्तक्षेप के बिना आपातकालीन नंबरों सहित, किसी भी फ़ोन नंबर पर कॉल करने देता है. दुर्भावनापूर्ण एप्स आपातकालीन सेवाओं पर अनावश्यक और अवैध कॉल कर सकते हैं."</string>
<string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"सीधे CDMA टेबलेट सेटअप प्रारंभ करें"</string>
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"सीधे CDMA फ़ोन सेटअप प्रारंभ करें"</string>
- <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"एप्लिकेशन को CDMA प्रावधान प्रारंभ करने देता है. दुर्भावनापूर्ण एप्लिकेशन अनावश्यक रूप से CDMA प्रावधान प्रारंभ कर सकते हैं."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"स्थान अपडेट सूचनाएं नियंत्रित करें"</string>
- <string name="permdesc_locationUpdates" msgid="1120741557891438876">"एप्लिकेशन को रेडियो से स्थान अपडेट सूचनाएं सक्षम/अक्षम करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"एप्स को CDMA प्रावधान प्रारंभ करने देता है. दुर्भावनापूर्ण एप्स अनावश्यक रूप से CDMA प्रावधान प्रारंभ कर सकते हैं."</string>
+ <string name="permlab_locationUpdates" msgid="7785408253364335740">"स्थान के बारे में नई जानकारी की सूचनाओं को नियंत्रित करें"</string>
+ <string name="permdesc_locationUpdates" msgid="1120741557891438876">"एप को रेडियो से स्थान के बारे में नई जानकारी की सूचनाएं सक्षम/अक्षम करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"चेकइन गुणों में पहुंचें"</string>
- <string name="permdesc_checkinProperties" msgid="4024526968630194128">"एप्स को चेकइन सेवा द्वारा अपलोड किए गए गुणों पर पढ़ें/लिखें पहुंच देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_checkinProperties" msgid="4024526968630194128">"एप्स को चेकइन सेवा द्वारा अपलोड किए गए गुणों पर पढ़ें/लिखें पहुंच देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"विजेट चुनें"</string>
- <string name="permdesc_bindGadget" msgid="8261326938599049290">"एप्स को सिस्टम को यह बताने देता है कि किस एप्स द्वारा कौन से विजेट का उपयोग किया जा सकता है. कोई एप्स, इस अनुमति के साथ अन्य एप्स के निजी डेटा पर पहुंच सकते हैं. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_bindGadget" msgid="8261326938599049290">"एप्स को सिस्टम को यह बताने देता है कि किस एप्स द्वारा कौन से विजेट का उपयोग किया जा सकता है. कोई एप्स, इस अनुमति के साथ अन्य एप्स के निजी डेटा पर पहुंच सकते हैं. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"फ़ोन स्थिति बदलें"</string>
- <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"एप्लिकेशन को उपकरण की फ़ोन सुविधाएं नियंत्रित करने देता है. इस अनुमति वाला कोई एप्लिकेशन आपको सूचित किए बिना नेटवर्क स्विच कर सकता है, फ़ोन का रेडियो चालू और बंद कर सकता है और ऐसे ही अन्य कार्य कर सकता है."</string>
+ <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"एप्स को उपकरण की फ़ोन सुविधाएं नियंत्रित करने देता है. इस अनुमति वाला कोई एप्स आपको सूचित किए बिना नेटवर्क स्विच कर सकता है, फ़ोन का रेडियो चालू और बंद कर सकता है और ऐसे ही अन्य कार्य कर सकता है."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"फ़ोन की स्थिति और पहचान पढ़ें"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"एप्स को उपकरण की फ़ोन सुविधाओं तक पहुंचने देता है. यह अनुमति एप्स को फ़ोन नंबर और उपकरण आईडी, कॉल सक्रिय है या नहीं, और कॉल द्वारा कनेक्ट किया गया दूरस्थ नंबर निर्धारित करने देती है."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टेबलेट को निष्क्रिय होने से रोकें"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फ़ोन को निष्क्रिय होने से रोकें"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"एप्स को टेबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"एप्स को फ़ोन को प्रयोग में नहीं होने से रोकता है."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"इंफ़्रारेड संचारित करें"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"एप्लिकेशन को टेबलेट के इंफ़्रारेड ट्रांसमीटर का उपयोग करने देती है."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"एप्लिकेशन को फ़ोन के इंफ़्रारेड ट्रांसमीटर का उपयोग करने देती है."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"टेबलेट चालू या बंद करें"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"फ़ोन चालू या बंद करें"</string>
- <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"एप्लिकेशन को टेबलेट चालू या बंद करने देता है."</string>
- <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"एप्लिकेशन को फ़ोन चालू या बंद करने देता है."</string>
+ <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"एप्स को टेबलेट चालू या बंद करने देता है."</string>
+ <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"एप्स को फ़ोन चालू या बंद करने देता है."</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"फ़ैक्ट्री परीक्षण मोड में चलाएं"</string>
<string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"टेबलेट हार्डवेयर में पूर्ण पहुंच की अनुमति देते हुए निम्न-स्तर निर्माता परीक्षण के रूप में चलाएं. केवल तभी उपलब्ध जब कोई टेबलेट निर्माता परीक्षण मोड में चल रहा हो."</string>
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"फ़ोन हार्डवेयर में पूर्ण पहुंच की अनुमति देते हुए निम्न-स्तर निर्माता परीक्षण के रूप में चलाएं. केवल तभी उपलब्ध जब कोई फ़ोन निर्माता परीक्षण मोड में चल रहा हो."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"वॉलपेपर सेट करें"</string>
- <string name="permdesc_setWallpaper" msgid="7373447920977624745">"एप्लिकेशन को सिस्टम वॉलपेपर सेट करने देता है."</string>
+ <string name="permdesc_setWallpaper" msgid="7373447920977624745">"एप्स को सिस्टम वॉलपेपर सेट करने देता है."</string>
<string name="permlab_setWallpaperHints" msgid="3278608165977736538">"अपने वॉलपेपर का आकार एडजस्ट करें"</string>
- <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"एप्लिकेशन को सिस्टम वॉलपेपर आकार संकेत सेट करने देता है."</string>
+ <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"एप्स को सिस्टम वॉलपेपर आकार संकेत सेट करने देता है."</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"फ़ैक्ट्री डिफ़ॉल्ट पर सिस्टम रीसेट करें"</string>
<string name="permdesc_masterClear" msgid="3665380492633910226">"एप्स को सभी डेटा, कॉन्फ़िगरेशन, और इंस्टॉल एप्स मिटाकर, सिस्टम को पूरी तरह उसकी फ़ैक्टरी सेटिंग पर रीसेट करने देता है."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"समय सेट करें"</string>
- <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"एप्लिकेशन को टेबलेट की घड़ी का समय बदलने देता है."</string>
- <string name="permdesc_setTime" product="default" msgid="1855702730738020">"एप्लिकेशन को फ़ोन की घड़ी का समय बदलने देता है."</string>
+ <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"एप्स को टेबलेट की घड़ी का समय बदलने देता है."</string>
+ <string name="permdesc_setTime" product="default" msgid="1855702730738020">"एप्स को फ़ोन की घड़ी का समय बदलने देता है."</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"समय क्षेत्र सेट करें"</string>
- <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"एप्लिकेशन को टेबलेट का समय क्षेत्र बदलने देता है."</string>
- <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"एप्लिकेशन को टेबलेट का समय क्षेत्र बदलने देता है."</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"एप्स को टेबलेट का समय क्षेत्र बदलने देता है."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"एप्स को टेबलेट का समय क्षेत्र बदलने देता है."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"खाता प्रबंधक सेवा के रूप में कार्य करें"</string>
- <string name="permdesc_accountManagerService" msgid="1948455552333615954">"एप्लिकेशन को खाता प्रमाणकों को कॉल करने देता है."</string>
+ <string name="permdesc_accountManagerService" msgid="1948455552333615954">"एप्स को खाता प्रमाणकों को कॉल करने देता है."</string>
<string name="permlab_getAccounts" msgid="1086795467760122114">"उपकरण पर खाते ढूंढें"</string>
<string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"एप्स को टेबलेट द्वारा ज्ञात खातों की सूची प्राप्त करने देता है. इसमें वे खाते शामिल हो सकते हैं जिन्हें आपके द्वारा इंस्टॉल किए गए एप्स ने बनाया है."</string>
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"एप्स को फ़ोन द्वारा ज्ञात खातों की सूची प्राप्त करने देता है. इसमें वे खाते शामिल हो सकते हैं जिन्हें आपके द्वारा इंस्टॉल किए गए एप्स ने बनाया है."</string>
<string name="permlab_authenticateAccounts" msgid="5265908481172736933">"खाते बनाएं और पासवर्ड सेट करें"</string>
<string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"एप्िलकेशन को खाता बनाने और उनके पासवर्ड प्राप्त करने और सेट करने सहित, खाता प्रबंधक की खाता प्रमाणक क्षमताओं का उपयोग करने देता है."</string>
<string name="permlab_manageAccounts" msgid="4983126304757177305">"खाते जोडें या निकालें"</string>
- <string name="permdesc_manageAccounts" msgid="8698295625488292506">"एप्लिकेशन को खाते जोड़ना और निकालना और उनके पासवर्ड हटाने जैसे कार्य करने देता है."</string>
+ <string name="permdesc_manageAccounts" msgid="8698295625488292506">"एप्स को खाते जोड़ना और निकालना और उनके पासवर्ड हटाने जैसे कार्य करने देता है."</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"उपकरण पर खातों का उपयोग करें"</string>
<string name="permdesc_useCredentials" msgid="7984227147403346422">"एप्स को प्रमाणीकरण टोकन का अनुरोध करने देता है."</string>
<string name="permlab_accessNetworkState" msgid="4951027964348974773">"नेटवर्क कनेक्शन देखें"</string>
@@ -582,9 +590,9 @@
<string name="permlab_changeNetworkState" msgid="958884291454327309">"नेटवर्क कनेक्टिविटी बदलें"</string>
<string name="permdesc_changeNetworkState" msgid="6789123912476416214">"एप्स को नेटवर्क कनेक्टिविटी की स्थिति बदलने देता है."</string>
<string name="permlab_changeTetherState" msgid="5952584964373017960">"टेदर की गई कनेक्टिविटी बदलें"</string>
- <string name="permdesc_changeTetherState" msgid="1524441344412319780">"एप्लिकेशन को टेदर की गई नेटवर्क कनेक्टिविटी की स्थिति बदलने देता है."</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"एप्स को टेदर की गई नेटवर्क कनेक्टिविटी की स्थिति बदलने देता है."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"पृष्ठभूमि डेटा उपयोग सेटिंग बदलें"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"एप्लिकेशन को पृष्ठभूमि डेटा उपयोग सेटिंग बदलने देता है."</string>
+ <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"एप्स को पृष्ठभूमि डेटा उपयोग सेटिंग बदलने देता है."</string>
<string name="permlab_accessWifiState" msgid="5202012949247040011">"Wi-Fi कनेक्शन देखें"</string>
<string name="permdesc_accessWifiState" msgid="5002798077387803726">"एप्स को Wi-Fi नेटवर्क के बारे में जानकारी, जैसे WI-Fi सक्षम है या नहीं और कनेक्ट किए गए Wi-Fi उपकरणों के नाम, देखने देता है."</string>
<string name="permlab_changeWifiState" msgid="6550641188749128035">"Wi-Fi से कनेक्ट और डिस्कनेक्ट करें"</string>
@@ -593,20 +601,20 @@
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"एप्स को Wi-Fi नेटवर्क पर मल्टीकास्ट पते के उपयोग से केवल आपके टेबलेट पर ही नहीं, बल्कि सभी उपकरणों पर भेजे गए पैकेट प्राप्त करने देता है. यह गैर-मल्टीकास्ट मोड से अधिक पावर का उपयोग करता है."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"एप्स को Wi-Fi नेटवर्क पर मल्टीकास्ट पते के उपयोग से केवल आपके फ़ोन पर ही नहीं, बल्कि सभी उपकरणों पर भेजे गए पैकेट प्राप्त करने देता है. यह गैर-मल्टीकास्ट मोड से अधिक पावर का उपयोग करता है."</string>
<string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"Bluetooth सेटिंग पर पहुंचें"</string>
- <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"किसी एप्लिकेशन को स्थानीय Bluetooth टेबलेट कॉन्फ़िगर करने की और रिमोट उपकरणों के साथ खोजने और युग्मित करने देता है."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"एप्लिकेशन को स्थानीय Bluetooth फ़ोन कॉन्फ़िगर करने देता है, और रिमोट उपकरणों के साथ खोजने और युग्मित करने देता है."</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"किसी एप्स को स्थानीय Bluetooth टेबलेट कॉन्फ़िगर करने की और रिमोट उपकरणों के साथ खोजने और युग्मित करने देता है."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"एप्स को स्थानीय Bluetooth फ़ोन कॉन्फ़िगर करने देता है, और रिमोट उपकरणों के साथ खोजने और युग्मित करने देता है."</string>
<string name="permlab_accessWimaxState" msgid="4195907010610205703">"WiMAX से कनेक्ट और डिस्कनेक्ट करें"</string>
<string name="permdesc_accessWimaxState" msgid="6360102877261978887">"एप्स को WiMAX सक्षम है या नहीं और कनेक्ट किए गए किसी WiMAX नेटवर्क के बारे में जानकारी निर्धारित करने देता है."</string>
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX स्थिति बदलें"</string>
- <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"एप्लिकेशन को WiMAX नेटवर्क से टेबलेट को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
- <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"एप्लिकेशन को WiMAX नेटवर्क से फ़ोन को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"एप्स को WiMAX नेटवर्क से टेबलेट को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"एप्स को WiMAX नेटवर्क से फ़ोन को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth उपकरणों के साथ युग्मित करें"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"एप्लिकेशन को टेबलेट पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
- <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"एप्लिकेशन को फ़ोन पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"एप्स को टेबलेट पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"एप्स को फ़ोन पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"नियर फ़ील्ड कम्यूनिकेशन नियंत्रित करें"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"एप्स को नियर फ़ील्ड कम्यूनिकेशन (NFC) टैग, कार्ड, और रीडर के साथ संचार करने देता है."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"अपना स्क्रीन लॉक अक्षम करें"</string>
- <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"एप्लिकेशन को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल समाप्त होने पर कीलॉक को पुन: सक्षम कर देता है."</string>
+ <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"एप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल समाप्त होने पर कीलॉक को पुन: सक्षम कर देता है."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"समन्वयन सेटिंग पढ़ें"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"एप्स को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह निर्धारित किया जा सकता है कि लोग एप्स किसी खाते के साथ समन्वयित है या नहीं."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"समन्वयन बंद या चालू टॉगल करें"</string>
@@ -614,11 +622,11 @@
<string name="permlab_readSyncStats" msgid="7396577451360202448">"समन्वयन आंकड़े पढ़ें"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"एप्स को किसी खाते के समन्वयन आंकड़े, साथ ही समन्वयित ईवेंट का इतिहास और समन्वयित डेटा की मात्रा पढ़ने देता है."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ग्राहकी-प्राप्त फ़ीड पढ़ें"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"एप्लिकेशन को वर्तमान में समन्वयित फ़ीड के बारे में विवरण प्राप्त करने देता है."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"एप्स को वर्तमान में समन्वयित फ़ीड के बारे में विवरण प्राप्त करने देता है."</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"ग्राहकी-प्राप्त फ़ीड लिखें"</string>
<string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"एप्स को आपके वर्तमान समन्वयित फ़ीड को संशोधित करने देता है. दुर्भावनापूर्ण एप्स आपके समन्वयित फ़ीड को बदल सकते है."</string>
<string name="permlab_readDictionary" msgid="4107101525746035718">"शब्दकोश में आपके द्वारा जोड़े गए शब्दों को पढ़ें"</string>
- <string name="permdesc_readDictionary" msgid="659614600338904243">"एप्लिकेशन को ऐसे सभी शब्दों, नामों और वाक्यांशों को पढ़ने देता है जो संभवत: उपयोगकर्ता द्वारा उपयोगकर्ता शब्दकोश में संग्रहीत किए गए हों."</string>
+ <string name="permdesc_readDictionary" msgid="659614600338904243">"एप्स को ऐसे सभी शब्दों, नामों और वाक्यांशों को पढ़ने देता है जो संभवत: उपयोगकर्ता द्वारा उपयोगकर्ता शब्दकोश में संग्रहीत किए गए हों."</string>
<string name="permlab_writeDictionary" msgid="2183110402314441106">"उपयोगकर्ता द्वारा परिभाषित शब्दकोश में शब्द जोड़ें"</string>
<string name="permdesc_writeDictionary" msgid="8185385716255065291">"एप्स को उपयोगकर्ता शब्दकोश में नए शब्द लिखने देता है."</string>
<string name="permlab_sdcardRead" product="nosdcard" msgid="8235341515605559677">"संरक्षित संग्रहण पर पहुंच का परीक्षण करें"</string>
@@ -636,15 +644,15 @@
<string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"सभी उपयोगकर्ताओं के बाहरी संग्रहण तक पहुंचें"</string>
<string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"एप्स को सभी उपयोगकर्ताओं के बाहरी संग्रहण तक पहुंचने दें."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"कैश फ़ाइल सिस्टम में पहंचे"</string>
- <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"एप्लिकेशन को संचय फ़ाइल सिस्टम पढ़ने और लिखने देता है."</string>
+ <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"एप्स को संचय फ़ाइल सिस्टम पढ़ने और लिखने देता है."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"इंटरनेट कॉल करें/प्राप्त करें"</string>
<string name="permdesc_use_sip" msgid="4717632000062674294">"एप्स को इंटरनेट कॉल करने/प्राप्त करने के लिए SIP सेवा का उपयोग करने देता है."</string>
<string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"ऐतिहासिक नेटवर्क उपयोग पढें"</string>
- <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"किसी एप्स को विशिष्ट नेटवर्क और एप्लिकेशन के लिए ऐतिहासिक नेटवर्क उपयोग को पढ़ने देता है."</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"किसी एप्स को विशिष्ट नेटवर्क और एप्स के लिए ऐतिहासिक नेटवर्क उपयोग को पढ़ने देता है."</string>
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"नेटवर्क नीति प्रबंधित करें"</string>
- <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्लिकेशन को नेटवर्क नीतियां प्रबंधित करने और एप्लिकेशन-विशिष्ट नियमों को परिभाषित करने देता है."</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्स को नेटवर्क नीतियां प्रबंधित करने और एप्स-विशिष्ट नियमों को परिभाषित करने देता है."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्स को यह संशोधित करने देता है कि एप्लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्स को यह संशोधित करने देता है कि एप्स की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_markNetworkSocket" msgid="3658527214914959749">"सॉकेट मार्क बदलें"</string>
<string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"एप्स को रूटिंग के लिए सॉकेट मार्क बदलने देता है"</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string>
@@ -652,11 +660,9 @@
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्स प्रारंभ करें"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्स प्रारंभ करने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्स प्रारंभ करने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"नेटवर्क स्थितियों के अवलोकनों को सुनें"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"एप्स को नेटवर्क स्थितियों के अवलोकनों को सुनने देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"हॉटवर्ड की पहचान का अनुरोध करें"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"एप्स को हॉटवर्ड की पहचान के लिए अनुरोध करने देती है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"स्क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
@@ -674,7 +680,7 @@
<string name="policylab_expirePassword" msgid="885279151847254056">"स्क्रीन लॉक करें पासवर्ड समाप्ति सेट करें"</string>
<string name="policydesc_expirePassword" msgid="1729725226314691591">"नियंत्रित करें कि कितने समय में लॉक-स्क्रीन पासवर्ड बदला जाना चाहिए."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"संग्रहण एन्क्रिप्शन सेट करें"</string>
- <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"संग्रहीत एप्लिकेशन डेटा को एन्क्रिप्ट किया जाना आवश्यक है."</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"संग्रहीत एप्स डेटा को एन्क्रिप्ट किया जाना आवश्यक है."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"कैमरों को अक्षम करें"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"सभी उपकरण कैमरों का उपयोग रोकें."</string>
<string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"कीगार्ड में सुविधाएं अक्षम करें"</string>
@@ -898,7 +904,7 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"रीबूट करें"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' पर यह पृष्ठ दर्शाता है:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"नेविगेशन की पुष्टि करें"</string>
+ <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"मार्गदर्शक की पुष्टि करें"</string>
<string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"इस पृष्ठ को छोड़ें"</string>
<string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"इस पृष्ठ पर बने रहें"</string>
<string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nक्या आप वाकई इस पृष्ठ से दूर नेविगेट करना चाहते हैं?"</string>
@@ -928,20 +934,20 @@
<string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"एप्स को आपके टेबलेट में संग्रहीत ब्राउज़र के इतिहास या बुकमार्क को संशोधित करने देता है. इससे एप्स ब्राउज़र डेटा को मिटा सकता है या संशोधित कर सकता है. ध्यान दें: यह अनुमति तृतीय-पक्ष ब्राउज़र या वेब ब्राउज़िंग क्षमताओं वाले अन्य एप्स द्वारा लागू नहीं की जा सकती."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"एप्स को आपके फ़ोन में संग्रहीत ब्राउज़र के इतिहास या बुकमार्क को संशोधित करने देता है. इससे एप्स ब्राउज़र डेटा को मिटा सकता है या संशोधित कर सकता है. ध्यान दें: यह अनुमति तृतीय-पक्ष ब्राउज़र या वेब ब्राउज़िंग क्षमताओं वाले अन्य एप्स द्वारा लागू नहीं की जा सकती."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"अलार्म सेट करें"</string>
- <string name="permdesc_setAlarm" msgid="316392039157473848">"एप्लिकेशन को इंस्टॉल किए गए अलार्म घड़ी एप्लिकेशन में अलार्म सेट करने देता है. हो सकता है कुछ अलार्म घड़ी एप्लिकेशन में यह सुविधा न हो."</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"एप्स को इंस्टॉल किए गए अलार्म घड़ी एप्स में अलार्म सेट करने देता है. हो सकता है कुछ अलार्म घड़ी एप्स में यह सुविधा न हो."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"ध्वनिमेल जोड़ें"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"एप्स को आपके ध्वनिमेल इनबॉक्स में संदेश जोड़ने देता है."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ब्राउज़र भौगोलिक-स्थान अनुमतियों को बदलें"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"एप्लिकेशन को ब्राउज़र के भौगोलिक-स्थान की अनुमतियां संशोधित करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग एकपक्षीय वेबसाइट को स्थान जानकारी भेजने में कर सकते हैं."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"एप्स को ब्राउज़र के भौगोलिक-स्थान की अनुमतियां संशोधित करने देता है. दुर्भावनापूर्ण एप्स इसका उपयोग एकपक्षीय वेबसाइट को स्थान जानकारी भेजने में कर सकते हैं."</string>
<string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"पैकेज सत्यापित करें"</string>
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"एप्लिकेशन को इंस्टॉल करने योग्य पैकेज सत्यापित करने देता है."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"पैकेज प्रमाणक से आबद्ध करें"</string>
- <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति देता है. सामान्य एप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"सीरियल पोर्ट पर पहुंचें"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API का उपयोग करके धारक को सीरियल पोर्ट पर पहुंच प्रदान करता है."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"बाह्य रूप से सामग्री प्रदाताओं पर पहुंच"</string>
<string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"धारक को शेल से सामग्री प्रदाताओं तक पहुंचने देता है. सामान्य एप्स के लिए कभी भी आवश्यकता नहीं होनी चाहिए."</string>
- <string name="permlab_updateLock" msgid="3527558366616680889">"स्वचालित उपकरण अपडेट का समर्थन न करें"</string>
+ <string name="permlab_updateLock" msgid="3527558366616680889">"अपनेआप उपकरण की नई जानकारी न लें"</string>
<string name="permdesc_updateLock" msgid="1655625832166778492">"धारक को उपकरण अपग्रेड करने के लिए, गैर-सहभागी रीबूट के ठीक समय के बारे में सिस्टम पर जानकारी प्रस्तुत करने देता है."</string>
<string name="save_password_message" msgid="767344687139195790">"क्या आप चाहते हैं कि ब्राउज़र पासवर्ड को याद रखे?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"अभी नहीं"</string>
@@ -959,7 +965,7 @@
<string name="searchview_description_query" msgid="5911778593125355124">"खोज क्वेरी"</string>
<string name="searchview_description_clear" msgid="1330281990951833033">"क्वेरी साफ़ करें"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"क्वेरी सबमिट करें"</string>
- <string name="searchview_description_voice" msgid="2453203695674994440">"ध्वनि खोज"</string>
+ <string name="searchview_description_voice" msgid="2453203695674994440">"बोलकर खोजें"</string>
<string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"स्पर्श के द्वारा अन्वेषण करें सक्षम करें?"</string>
<string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श के द्वारा अन्वेषण करें सक्षम करना चाहती है. स्पर्श के द्वारा अन्वेष करें चालू होने पर, आप अपनी अंगुली के नीचे क्या है उसका विवरण सुन सकते हैं या देख सकते हैं या टेबलेट से संवाद करने के लिए जेस्चर निष्पादित कर सकते हैं."</string>
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श के द्वारा अन्वेषण करें सक्षम करना चाहती है. स्पर्श के द्वारा अन्वेष करें चालू होने पर, आप अपनी अंगुली के नीचे क्या है उसका विवरण सुन सकते हैं या देख सकते हैं या फ़ोन से संवाद करने के लिए जेस्चर निष्पादित कर सकते हैं."</string>
@@ -1102,7 +1108,7 @@
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"सिस्टम सेटिंग > Apps > डाउनलोड किए गए में डिफ़ॉल्ट साफ करें."</string>
<string name="chooseActivity" msgid="7486876147751803333">"कोई क्रिया चुनें"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"USB उपकरण के लिए कोई एप्स चुनें"</string>
- <string name="noApplications" msgid="2991814273936504689">"कोई भी एप्लिकेशन यह कार्यवाही नहीं कर सकता."</string>
+ <string name="noApplications" msgid="2991814273936504689">"कोई भी एप्स यह कार्यवाही नहीं कर सकता."</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
<string name="aerr_application" msgid="932628488013092776">"दुर्भाग्यवश, <xliff:g id="APPLICATION">%1$s</xliff:g> रुक गया है."</string>
<string name="aerr_process" msgid="4507058997035697579">"दुर्भाग्यवश, <xliff:g id="PROCESS">%1$s</xliff:g> प्रक्रिया रुक गई है."</string>
@@ -1121,20 +1127,20 @@
<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">"इसे सिस्टम सेटिंग > Apps > डाउनलोड किए गए में पुन: सक्षम करें."</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_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>
<string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> में से <xliff:g id="NUMBER_0">%1$d</xliff:g> एप्स अनुकूलित हो रहा है."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"एप्स प्रारंभ होने वाले हैं"</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्त हो रहा है."</string>
<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_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="old_app_description" msgid="2082094275580358049">"नया एप्स प्रारंभ न करें."</string>
<string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> प्रारंभ करें"</string>
- <string name="new_app_description" msgid="1932143598371537340">"पुराने एप्लिकेशन को बिना सहेजे बंद करें."</string>
+ <string name="new_app_description" msgid="1932143598371537340">"पुराने एप्स को बिना सहेजे बंद करें."</string>
<string name="sendText" msgid="5209874571959469142">"पाठ के लिए किसी क्रिया को चुनें"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"रिंगर वॉल्यूम"</string>
<string name="volume_music" msgid="5421651157138628171">"मीडिया वॉल्यूम"</string>
@@ -1144,7 +1150,7 @@
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth कॉल के दौरान वॉल्यूम"</string>
<string name="volume_alarm" msgid="1985191616042689100">"अलार्म आवाज़"</string>
<string name="volume_notification" msgid="2422265656744276715">"सूचना वॉल्यूम"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"वॉल्यूम"</string>
+ <string name="volume_unknown" msgid="1400219669770445902">"आवाज़"</string>
<string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Bluetooth वॉल्यूम"</string>
<string name="volume_icon_description_ringer" msgid="3326003847006162496">"रिंगटोन वॉल्यूम"</string>
<string name="volume_icon_description_incall" msgid="8890073218154543397">"कॉल वॉल्यूम"</string>
@@ -1229,7 +1235,7 @@
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"USB संग्रहण बंद करें"</string>
<string name="usb_storage_stop_error_message" msgid="1970374898263063836">"USB संग्रहण बंद करने में कोई समस्या हुई थी. जांचें कि आपने USB होस्ट अनमाउंट किया है या नहीं, तब पुन: प्रयास करें."</string>
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"USB संग्रहण चालू करें"</string>
- <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"यदि आप USB संग्रहण चालू करते हैं, तो आपके द्वारा उपयोग किए जा रहे कुछ एप्लिकेशन रुक जाएंगे और हो सकता है कि वे तब तक अनुपलब्ध रहें जब तक कि आप USB संग्रहण बंद नहीं कर देते."</string>
+ <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"यदि आप USB संग्रहण चालू करते हैं, तो आपके द्वारा उपयोग किए जा रहे कुछ एप्स रुक जाएंगे और हो सकता है कि वे तब तक अनुपलब्ध रहें जब तक कि आप USB संग्रहण बंद नहीं कर देते."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"USB कार्यवाही विफल"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ठीक है"</string>
<string name="usb_mtp_notification_title" msgid="3699913097391550394">"किसी मीडिया उपकरण के रूप में कनेक्ट किया गया"</string>
@@ -1277,10 +1283,10 @@
<string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"USB संग्रहण निकाला गया. नया मीडिया सम्मिलित करें."</string>
<string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD कार्ड निकाला गया. एक नया सम्मिलित करें."</string>
<string name="activity_list_empty" msgid="1675388330786841066">"कोई मिलती-जुलती गतिविधि नहीं मिली."</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"घटक उपयोग आंकड़े अपडेट करें"</string>
- <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"एप्लिकेशन को घटक उपयोग के संकलित आंकड़े संशोधित करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"घटक उपयोग आंकड़ों की नई जानकारी पाएं"</string>
+ <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"एप्स को घटक उपयोग के संकलित आंकड़े संशोधित करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_copyProtectedData" msgid="4341036311211406692">"सामग्री की प्रतिलिपि बनाएं"</string>
- <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"एप्स को सामग्री की प्रतिलिपि बनाने के लिए डिफ़ॉल्ट कंटेनर सेवा शुरू करने देता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"एप्स को सामग्री की प्रतिलिपि बनाने के लिए डिफ़ॉल्ट कंटेनर सेवा शुरू करने देता है. सामान्य एप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_route_media_output" msgid="1642024455750414694">"मीडिया आउटपुट को रूट करें"</string>
<string name="permdesc_route_media_output" msgid="4932818749547244346">"एप्स को मीडिया आउटपुट को अन्य बाहरी उपकरणों पर रूट करने देता है."</string>
<string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"कीगार्ड सुरक्षित संग्रहण एक्सेस करें"</string>
@@ -1298,7 +1304,7 @@
<string name="ime_action_default" msgid="2840921885558045721">"निष्पादित करें"</string>
<string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g> के उपयोग द्वारा \n नंबर डायल करें"</string>
<string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g> का उपयोग करके\n संपर्क बनाएं"</string>
- <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"निम्न एक या अधिक एप्लिकेशन अभी और भविष्य में आपके खाते में पहुंच की अनुमति का अनुरोध करते हैं."</string>
+ <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"निम्न एक या अधिक एप्स अभी और भविष्य में आपके खाते में पहुंच की अनुमति का अनुरोध करते हैं."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"क्या आप इस अनुरोध को अनुमति देना चाहते हैं?"</string>
<string name="grant_permissions_header_text" msgid="6874497408201826708">"पहुंच अनुरोध"</string>
<string name="allow" msgid="7225948811296386551">"अनुमति दें"</string>
@@ -1395,7 +1401,7 @@
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</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">"कोई एप्लिकेशन चुनें"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"कोई एप्स चुनें"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"इसके साथ साझा करें:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ साझा करें"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"स्लाइडिंग हैंडल. स्पर्श करके रखें."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0a9db60..e9f5ed1 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše brisanja stavki <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Prostor za pohranu tabletnog računala pun je. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Prostor za pohranu na telefonu je pun. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadzire"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Od strane domene <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcije tabletnog uređaja"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opcije telefona"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Omogućuje aplikaciji upravljanje značajkama Wi-Fi zaslona niske razine."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"primanje audioizlaza"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Omogućuje aplikaciji primanje i preusmjeravanje audioizlaza."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Otkrivanje pokretača značajke"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Aplikaciji omogućuje snimanje zvuka radi otkrivanja pokretača značajke. Snimanje se može odvijati u pozadini, ali ne sprječava drugo snimanje zvuka (npr. kameru)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"primanje videoizlaza"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Omogućuje aplikaciji primanje i preusmjeravanje videoizlaza."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"primanje sigurnog videoizlaza"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečava telefon da prijeđe u stanje mirovanja"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Aplikaciji omogućuje sprječavanje prelaska tabletnog računala u mirovanje."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Aplikaciji omogućuje da spriječi prelazak telefona u mirovanje."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infracrveni prijenos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Aplikaciji omogućuje upotrebu infracrvenog odašiljača tableta."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Aplikaciji omogućuje upotrebu infracrvenog odašiljača telefona."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"uključivanje ili isključivanje tabletnog uređaja"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"uključivanje ili isključivanje telefona"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Aplikaciji omogućuje uključivanje i isključivanje tabletnog računala."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Dopušta nositelju pozivanje operaterove aplikacije za konfiguraciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"praćenje motrenja mrežnih uvjeta"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Omogućuje aplikaciji praćenje motrenja mrežnih uvjeta. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"zahtjev za prepoznavanje pokretača značajke"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Omogućuje aplikaciji da zahtijeva prepoznavanje pokretača značajke. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index f685f76..8343bb3 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Túl sok <xliff:g id="CONTENT_TYPE">%s</xliff:g> törlés."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"A táblagép tárhelye tele van. Szabadítson fel helyet néhány fájl törlésével."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"A telefon tárhelye megtelt. Hely felszabadításához töröljön néhány fájlt."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Lehet, hogy a hálózat felügyelt"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ismeretlen harmadik fél által"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Megfigyelő: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Saját"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Táblagép beállításai"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonbeállítások"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Lehetővé teszi, hogy az alkalmazás irányítsa a Wi-Fi kijelzők alacsonyabb szintű funkcióit."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"audiokimenet rögzítése"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Engedélyezi az alkalmazásnak a hangkimenet rögzítését és átirányítását."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotwordérzékelés"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Lehetővé teszi, hogy alkalmazás rögzítse a befelé jövő hangokat hotwordérzékelés céljából. A rögzítés végbemehet a háttérben, és nem zavarja a más jellegű hangrögzítést, például a kamera esetében."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"videokimenet rögzítése"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Engedélyezi az alkalmazásnak a videokimenet rögzítését és átirányítását."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"biztonságos videokimenet rögzítése"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefon alvó üzemmódjának megakadályozása"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a táblagép alvó üzemmódra váltson."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a telefon alvó üzemmódra váltson."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infravörös érzékelő"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Engedélyezi, hogy az alkalmazás használhassa a táblagép infravörös érzékelőjét."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Engedélyezi, hogy az alkalmazás használhassa a telefon infravörös érzékelőjét."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"a táblagép be- és kikapcsolása"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"a telefon be- és kikapcsolása"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Lehetővé teszi az alkalmazás számára a táblagép be- és kikapcsolását."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lehetővé teszi a használó számára a szolgáltató által biztosított konfigurációs alkalmazás hívását. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"hálózati körülményekkel kapcsolatos észrevételek figyelemmel kísérése"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lehetővé teszi egy alkalmazás számára, hogy figyelemmel kísérje a hálózati körülményekkel kapcsolatos észrevételeket. A normál alkalmazásoknak erre soha nincs szükségük."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"hotword-felismeréssel kapcsolatos kérelem"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Lehetővé teszi egy alkalmazás számára a hotword-felismeréssel kapcsolatos kérelmeket. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 1a33d67..97643c9 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Չափից շատ <xliff:g id="CONTENT_TYPE">%s</xliff:g> հեռացումներ:"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Գրասալիկի պահոցը լիքն է: Ջնջեք մի քանի ֆայլ` տարածք ազատելու համար:"</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_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>-ի կողմից"</string>
<string name="me" msgid="6545696007631404292">"Իմ"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Գրասալիկի ընտրանքները"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Հեռախոսի ընտրանքներ"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Թույլ է տալիս հավելվածին կառավարել WiFi ցուցադրիչների ցածր մակարդակի գործառույթները:"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"պահել աուդիո արտածումը"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Թույլ է տալիս ծրագրին պահել և վերահղել աուդիո արտածումը:"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Թեժ բառի հայտնաբերում"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Հավելվածին թույլ է տալիս որսալ ձայնանյութը՝ թեժ բառի հայտնաբերման համար: Դա կարող է տեղի ունենալ հետնաշերտում, սակայն չի խանգարի այլ աուդիո ձայնագրություններին (օր.՝ Տեսախցիկից):"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"պահել վիդեո արտածումը"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Թույլ է տալիս ծրագրին պահել և վերահղել վիդեո արտածումը:"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"պահել անվտանգ վիդեո արտածումը"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"կանխել հեռախոսի քնի ռեժիմին անցնելը"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Թույլ է տալիս հավելվածին կանխել գրասալիկի` քնի ռեժիմին անցնելը:"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Թույլ է տալիս հավելվածին կանխել հեռախոսի` քնի ռեժիմին անցնելը:"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"փոխանցել ինֆրակարմիր հաղորդիչով"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Հավելվածին թույլ է տալիս օգտագործել գրասալիկի ինֆրակարմիր հաղորդիչը:"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Հավելվածին թույլ է տալիս օգտագործել հեռախոսի ինֆրակարմիր հաղորդիչը:"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"գրասալիկը միացնել կամ անջատել"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"հեռախոսը միացնել կամ անջատել"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Թույլ է տալիս հավելվածին միացնել կամ անջատել գրասալիկը:"</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Թույլ է տալիս սեփականատիրոջը գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"լսել դիտարկումներ ցանցային պայմանների վերաբերյալ"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Հավելվածին թույլ է տալիս լսել դիտարկումներ ցանցային պայմանների վերաբերյալ: Սովորական հավելվածների համար երբեք պետք չի գալիս:"</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"ուղարկել թեժ բառի ճանաչման հայց"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Հավելվածին թույլ է տալիս թեժ բառի ճանաչման հայց ուղարկել: Սովորական հավելվածների համար երբեք պետք չի գալիս:"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Սահմանել գաղտնաբառի կանոնները"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Վերահսկել էկրանի ապակողպման գաղտնաբառերի թույլատրելի երկարությունն ու գրանշանները:"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Վերահսկել էկրանի ապակողպման փորձերը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 9080a41..6de81ac 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak <xliff:g id="CONTENT_TYPE">%s</xliff:g> penghapusan."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Penyimpanan tablet penuh. Hapus beberapa file untuk mengosongkan ruang."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Penyimpanan di ponsel penuh. Hapus sebagian file untuk mengosongkan ruang."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Jaringan mungkin dipantau"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Saya"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opsi tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opsi telepon"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Izinkan aplikasi mengontrol fitur tingkat rendah dari tampilan Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"tangkap keluaran audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Memungkinkan aplikasi menangkap dan mengalihkan keluaran audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Deteksi kata cepat"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Memungkinkan aplikasi menangkap audio untuk deteksi Kata Cepat. Penangkapan dapat berlangsung di latar belakang namun tidak akan mencegah penangkapan audio yang lain (misalnya Perekam video)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tangkap keluaran video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Memungkinkan aplikasi menangkap dan mengalihkan keluaran video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tangkap keluaran video aman"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"mencegah ponsel menjadi tidak aktif"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Mengizinkan apl mencegah tablet tidur."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Mengizinkan apl mencegah ponsel tidur."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"pancarkan inframerah"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Memungkinkan aplikasi menggunakan pemancar inframerah tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Memungkinkan aplikasi menggunakan pemancar inframerah ponsel."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"hidupkan atau matikan tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"daya ponsel hidup atau mati"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Mengizinkan apl menyalakan atau mematikan tablet."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Memungkinkan pemegang meminta aplikasi konfigurasi yang disediakan operator. Tidak pernah diperlukan aplikasi normal."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"mendengar untuk observasi kondisi jaringan"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Memungkinkan aplikasi mendengar untuk observasi kondisi jaringan. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"meminta pengenalan kata cepat"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Memungkinkan aplikasi meminta pengenalan kata cepat. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 5891bbb..5ae7c5f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Troppe eliminazioni di <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Spazio di archiviazione del tablet esaurito. Elimina alcuni file per liberare spazio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"La rete potrebbe essere monitorata"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Da una terza parte sconosciuta"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Da <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Io"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opzioni tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opzioni telefono"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Consente all\'applicazione di controllare le funzioni di basso livello di schermi Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"acquisizione dell\'uscita audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Consente all\'app di acquisire e reindirizzare l\'uscita audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Rilevamento hotword"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Consente all\'app di acquisire l\'audio per il rilevamento Hotword. L\'acquisizione può avvenire in background ma non impedisce l\'acquisizione di altro audio (ad esempio con la videocamera)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"acquisizione dell\'uscita video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Consente all\'app di acquisire e reindirizzare l\'uscita video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"acquisizione dell\'uscita video sicura"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Consente all\'applicazione di impedire lo stand-by del tablet."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Consente all\'applicazione di impedire lo stand-by del telefono."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"trasmissione a infrarossi"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Consente all\'app di utilizzare il trasmettitore a infrarossi del tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Consente all\'app di utilizzare il trasmettitore a infrarossi del telefono."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"accensione o spegnimento del tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"accensione o spegnimento del telefono"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Consente all\'applicazione di accendere o spegnere il tablet."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascolto delle osservazioni sulle condizioni di rete"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Consente a un\'applicazione di ascoltare le osservazioni sulle condizioni di rete. Da non utilizzare mai con app normali."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"richiesta di riconoscimento hotword"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Consente a un\'applicazione di richiedere il riconoscimento hotword. Da non utilizzare mai con app normali."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Imposta regole password"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitora tentativi di sblocco dello schermo"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 27e4a89..b9eecd0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"יש מחיקות רבות מדי של <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"שטח האחסון של הטבלט מלא. מחק קבצים כדי לפנות מקום."</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_managed" msgid="4030263497686867141">"על ידי <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"אני"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"אפשרויות טאבלט"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"אפשרויות טלפון"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"מאפשר לאפליקציה לשלוט בתכונות ברמה נמוכה של תצוגות Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"קליטת פלט אודיו"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"מאפשרת לאפליקציה לקלוט ולהפנות מחדש פלט אודיו."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"זיהוי של מילת הפעלה"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"מאפשרת לאפליקציה לקלוט אודיו עבור זיהוי של מילת הפעלה. פעולת הקליטה יכולה להתבצע ברקע, אבל לא מונעת קליטת אודיו אחרת (למשל, במצלמת הווידאו)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"קליטת פלט וידאו"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"מאפשרת לאפליקציה לקלוט ולהפנות מחדש פלט וידאו."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"קליטת פלט וידאו מאובטח"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"מניעת מעבר הטלפון למצב שינה"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"מאפשר ליישום למנוע מהטבלט לעבור למצב שינה."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"מאפשר ליישום למנוע מהטלפון לעבור למצב שינה."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"שידור באינפרא-אדום"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"מאפשרת לאפליקציה להשתמש במשדר האינפרא-אדום של הטאבלט."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"מאפשרת לאפליקציה להשתמש במשדר האינפרא-אדום של הטלפון."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"הפעלה או כיבוי של טאבלט"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"הפעל או כבה את הטלפון"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"מאפשר ליישום להפעיל או לכבות את הטבלט."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ההרשאה הזו מאפשרת לבעלים להפעיל את אפליקציית התצורה שסופקה על ידי ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"קליטת מעקב אחר תנאי רשת"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"מאפשרת לאפליקציה לקלוט מעקב אחר תנאי רשת. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"בקשה של הכרה במילת הפעלה"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"מאפשרת לאפליקציה לבקש הכרה במילת הפעלה. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
@@ -812,7 +818,7 @@
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"נכון!"</string>
<string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"נסה שוב"</string>
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"נסה שוב"</string>
- <string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פרצוף"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פנים"</string>
<string name="lockscreen_plugged_in" msgid="8057762828355572315">"טוען (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<string name="lockscreen_charged" msgid="321635745684060624">"טעון"</string>
<string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
@@ -878,7 +884,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"הרחב את אזור ביטול הנעילה."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ביטול נעילה באמצעות הסטה."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ביטול נעילה באמצעות ציור קו."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פרצוף."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פנים."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ביטול נעילה באמצעות מספר PIN."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ביטול נעילה באמצעות סיסמה."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"אזור ציור קו."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 93bb912..c2401bc 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>での削除が多すぎます。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"タブレットのストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"端末のストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ネットワークが監視される場合があります"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"自分"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"タブレットオプション"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"携帯電話オプション"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Wi-Fiディスプレイの低レベル機能を制御することをアプリに許可します。"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"音声出力のキャプチャ"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"音声出力のキャプチャとリダイレクトをアプリに許可します。"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"注目ワード検出"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"注目ワード検出での音声キャプチャをアプリに許可します。キャプチャはバックグラウンドで発生しますが、その他の音声キャプチャ(例: ビデオ録画)を妨げることはありません。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"動画出力のキャプチャ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"動画出力のキャプチャとリダイレクトをアプリに許可します。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"セキュリティ保護された動画出力のキャプチャ"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"端末のスリープを無効にする"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"タブレットのスリープを無効にすることをアプリに許可します。"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"携帯端末のスリープを無効にすることをアプリに許可します。"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"赤外線の送信"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"タブレットの赤外線送信機能の使用をアプリに許可します。"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"携帯電話の赤外線送信機能の使用をアプリに許可します。"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"タブレットの電源ON/OFF"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"電源のON/OFF"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"タブレットの電源のON/OFFをアプリに許可します。"</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"携帯通信会社が提供する設定アプリを呼び出すことを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ネットワーク状況監視のためのリッスン"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ネットワーク状況を監視するためリッスンすることをアプリに許可します。通常のアプリで必要になることはありません。"</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"注目ワードの認識のリクエスト"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"注目ワードの認識のリクエストをアプリに許可します。通常のアプリでは不要です。"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 87b9fa5..e4e5f92 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>-ის ძალიან ბევრი წაშლილები."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ტაბლეტის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ტელეფონის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"შესაძლოა ქსელი მონიტორინგის ქვეშ იმყოფება"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"მე"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"ტაბლეტის პარამეტრები"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"ტელეფონის პარამეტრები"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"აპს შეეძლება აკონტროლოს Wifi ეკრანების დაბალი დონის ფუნქციები."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"გამომავალი აუდიოს დაჭერა"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"საშუალებას აძლევს აპს დაიჭიროს და გადაამისამართოს გამომავალი აუდიო."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ჯადოსნური სიტყვის პოვნა"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"საშუალებას აძლევს აპს ჩაიწეროს აუდიო ჯადოსნნური სიტყვების ამოცნობისათვის. ჩაწერა შესაძლოა განხორციელდეს ფონურად, თუმცა ხელს არ უშლის სხვა სახის აუდიოს ჩაწერას (მაგ. ვიდეოჩამწერიდან)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"გამომავალი ვიდეოს დაჭერა"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"საშუალებას აძლევს აპს დაიჭიროს და გადაამისამართოს გამომავალი ვიდეო."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"გამომავალი დაცული ვიდეოს დაჭერა"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ტელეფონის ძილის რეჟიმში გადასვლის აღკვეთა"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"აპს შეეძლება ხელი შეუშალოს ტაბლეტის დაძინებას."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"აპს შეეძლება ხელი შეუშალოს ტელეფონის დაძინებას."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ინფრაწითელით გადაცემა"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"რთავს ნებას აპს გამოიყენოს ტაბლეტის ინფრაწითელი გადამცემი."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"რთავს ნებას აპს გამოიყენოს ტელეფონის ინფრაწითელი გადამცემი."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ტაბლეტის ჩართვა ან გამორთვა"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ტელეფონის ჩართვა ან გამორთვა"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"აპს შეეძლება, ჩართოს ან გამორთოს ტაბლეტი."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"საშუალებას აძლევს მფლობელს გამოიწვიოს ოპერატორის მიერ მოწოდებული კონფიგურაციის აპი. ჩვეულებრივ აპს ეს წესით არასოდეს არ უნდა დაჭირდეს."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"განხორციელდეს ქსელის მდგომარეობის მონიტორინგი"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"საშუალებას აძლევს აპლიკაციებს განახორციელოს ქსელის მდგომარეობის მონიტორინგი. ეს ფუნქცია ჩვეულებრივ აპებს არ ჭირდება."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"ჯადოსნური სიტყვის ამოცნობის მოთხოვნა"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"საშუალებას აძლევს აპლიკაციებს განახორციელოს ჯადოსნური სიტყვის ამოცნობა. ეს ფუნქცია ჩვეულებრივ აპებს არ ჭირდება."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"პაროლის წესების დაყენება"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"გააკონტროლეთ ეკრანის განბლოკვის პაროლში დაშვებული სიმბოლოები და მისი სიგრძე."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ეკრანის განბლოკვის მცდელობების გაკონტროლება"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index f92dc78..f56d261 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"មានការលុប <xliff:g id="CONTENT_TYPE">%s</xliff:g> ច្រើនពេក។"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ឧបករណ៍ផ្ទុកនៃកុំព្យូទ័របន្ទះពេញ។ លុបឯកសារមួយចំនួន។"</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_managed" msgid="4030263497686867141">"ដោយ <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"ខ្ញុំ"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"ជម្រើសកុំព្យូទ័របន្ទះ"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"ជម្រើសទូរស័ព្ទ"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ឲ្យកម្មវិធីពិនិត្យលក្ខណៈកម្រិតទាបនៃការបង្ហាញវ៉ាយហ្វាយ។"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ចាប់យកលទ្ធផលអូឌីយ៉ូ"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ឱ្យកម្មវិធីដើម្បីចាប់យក និងប្ដូរទិសលទ្ធផលអូឌីយ៉ូ។"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ការរកឃើញពាក្យ"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"ឲ្យកម្មវិធីថតអូឌីយ៉ូសម្រាប់ការរកឃើញពាក្យ។ ការថតអាចកើតឡើងក្នុងផ្ទៃខាងក្រោយ ប៉ុន្តែមិនរារាំងការថតអូឌីយ៉ូផ្សេងទេ (ឧ. ម៉ាស៊ីនថតវីដេអូ)។"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ចាប់យកលទ្ធផលវីដេអូ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"ឲ្យកម្មវិធីចាប់យក និងប្ដូរទិសលទ្ធផលវីដេអូ។"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ចាប់យកលទ្ធផលវីដេអូសុវត្ថិភាព"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ការពារទូរស័ព្ទមិនឲ្យដេក"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ឲ្យកម្មវិធីការពារកុំព្យូទ័របន្ទះមិនឲ្យដេក។"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ឲ្យកម្មវិធីការពារទូរស័ព្ទមិនឲ្យដេក។"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"បញ្ជូនអ៊ីនហ្វ្រារ៉េដ"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"ឲ្យកម្មវិធីប្រើកម្មវិធីបញ្ជូនអ៊ីនហ្វ្រារ៉េដរបស់កុំព្យូទ័របន្ទះ។"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"ឲ្យកម្មវិធីប្រើកម្មវិធីបញ្ជូនតាមអ៊ីនហ្វ្រារ៉េដរបស់ទូរស័ព្ទ។"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"បិទ/បើកកុំព្យូទ័របន្ទះ"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"បិទ/បើកទូរស័ព្ទ"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"ឲ្យកម្មវិធីបិទ/បើកកុំព្យូទ័របន្ទះ។"</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"អនុញ្ញាតឲ្យម្ចាស់ដកហូតកម្មវិធីកំណត់រចនាសម្ព័ន្ធដែលបានផ្ដល់ដោយក្រុមហ៊ុនបញ្ជូន។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"សង្កេតមើលលើលក្ខខណ្ឌបណ្ដាញ"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ឲ្យកម្មវិធីសង្កេតមើលលើលក្ខខណ្ឌបណ្ដាញ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"ស្នើការស្គាល់ hotword"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"ឲ្យកម្មវិធីស្នើការស្គាល់ hotword ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"កំណត់ក្បួនពាក្យសម្ងាត់"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"ពិនិត្យប្រវែង និងតួអក្សរដែលបានអនុញ្ញាតក្នុងពាក្យសម្ងាត់ចាក់សោអេក្រង់។"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ពិនិត្យការព្យាយាមដោះសោអេក្រង់"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 4938124..41e66ce 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"태블릿 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"휴대전화 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장공간을 늘리세요."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"네트워크가 모니터링될 수 있음"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"나"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"태블릿 옵션"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"휴대전화 옵션"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"앱이 Wi-Fi 디스플레이의 하위 수준 기능을 제어하도록 허용합니다."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"오디오 출력 캡처"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"앱이 오디오 출력을 캡처하고 리디렉션하도록 허용합니다."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"핫워드 감지"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"앱에서 핫워드 감지를 위해 오디오를 캡처하도록 허용합니다. 캡처는 백그라운드에서 수행될 수 있지만 다른 오디오 캡처를 차단하지 않습니다(예: 캠코더)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"동영상 출력 캡처"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"앱이 동영상 출력을 캡처하고 리디렉션하도록 허용합니다."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"안전한 동영상 출력 캡처"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"앱이 태블릿의 절전 모드 전환을 막도록 허용합니다."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"앱이 휴대전화의 절전 모드 전환을 막도록 허용합니다."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"적외선 전송"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"앱에서 태블릿의 적외선 송신기를 사용하도록 허용합니다."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"앱에서 휴대전화의 적외선 송신기를 사용하도록 허용합니다."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"태블릿 전원 켜고 끄기"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"휴대전화 전원 켜고 끄기"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"앱이 태블릿을 켜거나 끌 수 있도록 허용합니다."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"권한을 가진 프로그램이 이동통신사에서 제공한 구성 앱을 호출하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"네트워크 상태에 대한 관측 보고 수신"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"애플리케이션이 네트워크 상태에 대한 관측 보고를 수신하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"핫워드 감지 요청"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"애플리케이션이 핫워드 감지를 요청할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
@@ -672,7 +680,7 @@
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"기기 전체 프록시 설정"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"정책이 사용 설정되어 있는 동안 사용될 기기 전체 프록시를 설정합니다. 첫 번째 기기 관리자가 설정한 전체 프록시만 유효합니다."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"화면 잠금 비밀번호 만료 설정"</string>
- <string name="policydesc_expirePassword" msgid="1729725226314691591">"화면 잠금 비밀번호 변경 빈도 설정"</string>
+ <string name="policydesc_expirePassword" msgid="1729725226314691591">"화면 잠금 비밀번호 변경 빈도를 설정합니다."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"저장소 암호화 설정"</string>
<string name="policydesc_encryptedStorage" msgid="2637732115325316992">"저장한 애플리케이션 데이터를 암호화해야 합니다."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"카메라 사용 안함"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 2aeab50..9d088f6 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"ມີການລຶບ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ຫຼາຍເກີນໄປ."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນໃນແທັບເລັດເຕັມ. ລຶບບາງໄຟລ໌ອອກເພື່ອເພີ່ມພື້ນທີ່ຫວ່າງ."</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_managed" msgid="4030263497686867141">"ໂດຍ <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"ຂ້າພະເຈົ້າ"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"ໂຕເລືອກແທັບເລັດ"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"ໂຕເລືອກໂທລະສັບ"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ອະນຸຍາດໃຫ້ແອັບຯ ຄວບຄຸມຄວາມສາມາດລະດັບຕໍ່າຂອງການສະແດງຜົນ Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ບັນທຶກສຽງອອກ"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ອະນຸຍາດໃຫ້ແອັບຯບັນທຶກ ແລະປ່ຽນເສັ້ນທາງການປ້ອນຂໍ້ມູນອອກຂອງສຽງ."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ການກວດຫາ Hotword"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"ອະນຸຍາດໃຫ້ແອັບຯຈັບຂໍ້ມູນສຽງສຳລັບການກວດຈັບ Hotword. ການຈັບຂໍ້ມູນສາມາດເກີດຂຶ້ນໃນພື້ນຫຼັງໄດ້ ແຕ່ຈະບໍ່ໄປຂັດຂວາງການຈັບຂໍ້ມູນສຽງອື່ນໆ (ເຊັ່ນ: ກ້ອງວິດີໂອ)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ບັນທຶກວິດີໂອອອກ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"ອະນຸຍາດໃຫ້ແອັບຯບັນທຶກ ແລະປ່ຽນເສັ້ນທາງການປ້ອນຂໍ້ມູນອອກຂອງວິດີໂອ."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ບັນທຶກວິດີໂອອອກຢ່າງປອດໄພ"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ຂັດຂວາງບໍ່ໃຫ້ໂທລະສັບປິດໜ້າຈໍ"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ອະນຸຍາດໃຫ້ແອັບຯ ປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"ອະນຸຍາດໃຫ້ແອັບຯປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍໂທລະສັບ."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ສົ່ງອິນຟຣາເຣດ"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ການສົ່ງອິນຟຣາເຣດຂອງແທັບເລັດໄດ້."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ການສົ່ງອິນຟຣາເຣດຂອງໂທລະສັບໄດ້."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ເປີດ ຫຼືປິດແທັບເລັດ"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ເປີດ ຫຼືປິດໂທລະສັບ"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"ອະນຸຍາດໃຫ້ແອັບຯເປີດ ຫຼືປິດແທັບເລັດ."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ. ບໍ່ໜ້າຈະຕ້ອງການສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັ່ນຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ. ປົກກະຕິແລ້ວແອັບຯທຳມະດາຈະບໍ່ຕ້ອງການໃຊ້."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"ຮ້ອງຂໍການຮັບຮູ້ hotword"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນຮ້ອງຂໍການຮັບຮູ້ hotword. ສ່ວນໃຫຍ່ບໍ່ໄດ້ໃຊ້ໃນແອັບຯທົ່ວໄປ."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"ຕັ້ງຄ່າກົດຂອງລະຫັດຜ່ານ"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"ຄວບຄຸມຄວາມຍາວຂອງໂຕອັກສອນທີ່ສາມາດໃຊ້ກັບລະຫັດປົດລັອກໜ້າຈໍ"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ຕິດຕາມການພະຍາຍາມປົດລັອກໜ້າຈໍ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 77a5924..c575a21 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Per daug <xliff:g id="CONTENT_TYPE">%s</xliff:g> trynimo."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetinio kompiuterio atmintis pilna. Kad atlaisvintumėte vietos, ištrinkite kelis failus."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefono atmintis pilna. Ištrinkite kai kuriuos failus, kad atlaisvintumėte vietos."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Tinklas gali būti stebimas"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nežinoma trečioji šalis"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Aš"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Planšetinio kompiuterio parinktys"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefono parinktys"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Leidžiama programai valdyti „Wi-Fi“ pateikčių žemo lygio funkcijas."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"fiksuoti garso išvestį"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Programai leidžiama fiksuoti ir peradresuoti garso išvestį."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Aktyvinamųjų žodžių aptikimas"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Programai leidžiama įrašyti garsą, kad būtų galima aptikti aktyvinamuosius žodžius. Įrašymas gali būti vykdomas fone, bet tai netrikdo kitų garso įrašymo veiksmų (pvz., įrašymo vaizdo kamera)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"fiksuoti vaizdo išvestį"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Programai leidžiama fiksuoti ir peradresuoti vaizdo išvestį."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"fiksuoti saugią vaizdo išvestį"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"neleisti telefonui snausti"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Leidžiama programai neleisti planšetiniam kompiuteriui užmigti."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Leidžiama programai neleisti telefonui užmigti."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"perduoti duomenis infraraudonaisiais spinduliais"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Programai leidžiama naudoti planšetinio kompiuterio infraraudonųjų spindulių perdavimo įrenginį."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Programai leidžiama naudoti telefono infraraudonųjų spindulių perdavimo įrenginį."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"įjungti arba išjungti planšetinį kompiuterį"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"telefono įjungimas ir išjungimas"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Leidžiama programai įjungti ar išjungti planšetinį kompiuterį."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Turėtojui leidžiama iškviesti operatoriaus pateiktą konfigūravimo programą. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"vykdyti tinklo sąlygų stebėjimą"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Leidžiama programai vykdyti tinklo sąlygų stebėjimą. To niekada neturėtų prireikti naudojant įprastas programas."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"teikti aktyvinamojo žodžio atpažinimo užklausas"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Programai leidžiama teikti aktyvinamojo žodžio atpažinimo užklausas. To niekada neturėtų prireikti naudojant įprastas programas."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 3f53a00..0dda696 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Pārāk daudz <xliff:g id="CONTENT_TYPE">%s</xliff:g> dzēsto vienumu."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetdatora atmiņa ir pilna. Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Tālruņa atmiņa ir pilna! Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nezināma trešā puse"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Domēns <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Man"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Planšetdatora opcijas"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Tālruņa opcijas"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Ļauj lietotnei kontrolēt zema līmeņa funkcijas Wi-Fi displejos."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"tvert audio izvadi"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Ļauj lietotnei tvert un novirzīt audio izvadi."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Īsinājumvārda noteikšana"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Ļauj lietotnei tvert audio īsinājumvārda noteikšanai. Tveršana var notikt fonā, taču tā neaizkavē citu audio (piemēram, videokameras audio) tveršanu."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tvert video izvadi"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Ļauj lietotnei tvert un novirzīt video izvadi."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tvert drošu video izvadi"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"novērst tālruņa pāriešanu miega režīmā"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ļauj lietotnei novērst planšetdatora pāriešanu miega režīmā."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ļauj lietotnei novērst tālruņa pāriešanu miega režīmā."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"pārraidīt infrasarkano staru signālu"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Ļauj lietotnei izmantot planšetdatora infrasarkano staru signāla raidītāju."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Ļauj lietotnei izmantot tālruņa infrasarkano staru signāla raidītāju."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ieslēgt vai izslēgt planšetdatoru"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ieslēgt vai izslēgt tālruni"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Ļauj lietotnei ieslēgt vai izslēgt planšetdatoru."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ļauj īpašniekam izsaukt operatora nodrošināto konfigurācijas lietotni. Parastām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"iegūt informāciju par tīkla stāvokļa novērojumiem"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ļauj lietojumprogrammai iegūt informāciju par tīkla stāvokļa novērojumiem. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"pieprasīt īsinājumvārdu atpazīšanu"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Ļauj lietojumprogrammai pieprasīt īsinājumvārdu atpazīšanu. Parastajām lietotnēm šī atļauja nav nepieciešama."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 12a40cf..b456d3e 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Хэт олон <xliff:g id="CONTENT_TYPE">%s</xliff:g> устгах."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Таблетийн сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</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_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>-с"</string>
<string name="me" msgid="6545696007631404292">"Би"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Таблетын сонголтууд"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Утасны сонголт"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Апп нь Wifi дэлгэцний доод-төвшиний функцийг удирдах боломжтой."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"аудио гаралтыг барих"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Апп-т аудио гаралтыг барих, дахин чиглүүлэхийг зөвшөөрнө."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Хотворд таних"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Апп-д Хотворд илрүүлэхийн тулд аудиог бичихийг зөвшөөрнө. Бичилт далд хийгдэх бөгөөд бусад аудио бичилтэд (жнь. видео бичлэг) саад болохгүй."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"видео гаралтыг барих"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Апп-т видео гаралтыг барих, дахин чиглүүлэхийг зөвшөөрнө."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"найдвартай видео гаралтыг барих"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"утсыг унтуулахгүй байлгах"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Апп нь таблетыг унтахаас сэргийлэх боломжтой"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Апп нь утсыг унтахаас сэргийлэх боломжтой"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"хэт улаанаар дамжуулах"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Апп-д таблетын хэт улаан дамжуулагчийг ашиглахыг зөвшөөрнө."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Апп-д утасны хэт улаан дамжуулагчийг ашиглахыг зөвшөөрнө."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"таблетыг унтраах эсвэл асаах"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"утсыг унтраах эсвэл асаах"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Апп нь таблетыг асаах, унтраах боломжтой."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Эзэмшигчид үүрэн компанийн нийлүүлсэн тохируулах апп-г өдөөх боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Сүлжээний байдлын талаар ажиглалтуудыг хүлээн авах"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Аппликешнд сүлжээний байдлын талаар ажиглалтуудыг хүлээн авахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"хотворд таних хүсэлт"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Аппликешнд хотворд таних хүсэлт гаргахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Нууц үгний дүрмийг тохируулах"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Дэлгэц түгжих нууц үгэнд зөвшөөрөгдсөн тэмдэгт болон уртыг удирдах"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Дэлгэц тайлах оролдлогыг хянах"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 552f390..b266591 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak pemadaman <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Storan tablet penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Storan telefon penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rangkaian mungkin dipantau"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Saya"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Pilihan tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Pilihan telefon"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Membenarkan apl mengawal ciri tahap rendah paparan Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"tangkap output audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Membenarkan apl menangkap dan mengubah hala output audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Pengesanan sebutan laluan"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Benarkan apl merakam audio untuk pengesahan Sebutan Laluan. Rakaman ini boleh berlaku di latar belakang tetapi tidak menghalang rakaman audio lain (cth. Kamkorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tangkap output video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Membenarkan apl menangkap dan mengubah hala output video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tangkap output video selamat"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"halang telefon daripada tidur"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Membenarkan apl menghalang tablet daripada tidur."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Membenarkan apl menghalang telefon daripada tidur."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"hantar inframerah"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Membenarkan apl menggunakan pemancar inframerah tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Membenarkan apl menggunakan pemancar inframerah telefon."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"menghidupkan atau mematikan kuasa tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"kuasakan telefon hidup atau mati"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Membenarkan apl menghidupkan atau mematikan tablet."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Membenarkan pemegang menggunakan apl konfigurasi yang diberikan oleh pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"dengar pemerhatian mengenai keadaan rangkaian"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Membenarkan aplikasi mendengar pemerhatian tentang keadaan rangkaian. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"minta pengecaman sebutan laluan"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Membenarkan aplikasi meminta pengecaman sebutan laluan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index ffc38c2..c0d58aa 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Nettbrettlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nettverket blir muligens overvåket"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en ukjent tredjepart"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Av <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Meg"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Innstillinger for nettbrettet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefoninnstillinger"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillater appen å kontrollere lavnivåfunksjoner i Wi-Fi-skjermer."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ta opp fra lydutdata"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Lar appen ta opp og omdirigere lydutdata."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Gjenkjennelse av kommandoord"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Gir appen tillatelse til å ta opp lyd for å gjenkjenne kommandoord. Opptaket kan skje i bakgrunnen, men forhindrer ikke lydopptak i andre funksjoner (f.eks. i videoopptak)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ta opp fra videoutdata"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Lar appen ta opp og omdirigere videoutdata."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ta opp fra sikre videoutdata"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"forhindre telefonen fra å sove"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lar appen hindre nettbrettet fra å gå over i sovemodus."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Lar appen hindre telefonen fra å gå over i sovemodus."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infrarød overføring"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Gir appen tillatelse til å bruke nettbrettets infrarøde sender."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Gir appen tillatelse til å bruke telefonens infrarøde sender."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"slå på eller av nettbrettet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"slå telefonen av eller på"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Lar appen slå på eller av nettbrettet."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Gir innehaveren tillatelse til å kalle opp den konfigurasjonsappen som ble levert av operatøren. Dette skal ikke være nødvendig for vanlige apper."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lytte etter observasjoner om nettverksforhold"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Gir appen tillatelse til å lytte etter observasjoner om nettverksforhold. Dette skal ikke være nødvendig for vanlige apper."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"forespørsel om gjenkjenning via kommandoord"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Gir appen tillatelse til å be om gjenkjenning via kommandoord. Dette skal ikke være nødvendig for vanlige apper."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index a1d5686..3a97f95 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel verwijderen voor <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletgeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefoongeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan worden gecontroleerd"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Door een onbekende derde partij"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Door <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ik"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tabletopties"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefoonopties"</string>
@@ -436,12 +439,12 @@
<string name="permlab_writeContacts" msgid="5107492086416793544">"uw contacten aanpassen"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Hiermee kan de app gegevens wijzigen over de contacten die zijn opgeslagen op uw tablet, inclusief de frequentie waarmee u heeft gebeld, gemaild of op andere manieren heeft gecommuniceerd met specifieke contacten. Met deze toestemming kunnen apps contactgegevens verwijderen."</string>
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Hiermee kan de app gegevens wijzigen over de contacten die zijn opgeslagen op uw telefoon, inclusief de frequentie waarmee u heeft gebeld, gemaild of op andere manieren heeft gecommuniceerd met specifieke contacten. Met deze toestemming kunnen apps contactgegevens verwijderen."</string>
- <string name="permlab_readCallLog" msgid="3478133184624102739">"oproeplogboek lezen"</string>
- <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Hiermee kan de app het oproeplogboek van uw tablet lezen, inclusief gegevens over inkomende en uitgaande oproepen. Met deze toestemming kunnen apps uw oproeploggegevens opslaan, en schadelijke apps kunnen logoproepgegevens zonder uw medeweten delen."</string>
- <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Hiermee kan de app het oproeplogboek van uw telefoon lezen, inclusief gegevens over inkomende en uitgaande oproepen. Met deze toestemming kunnen apps uw oproeploggegevens opslaan, en schadelijke apps kunnen logoproepgegevens zonder uw medeweten delen."</string>
- <string name="permlab_writeCallLog" msgid="8552045664743499354">"oproeplogboek schrijven"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Toestaan dat de app het oproeplogboek van uw tablet aanpast, waaronder gegevens over inkomende en uitgaande oproepen. Schadelijke apps kunnen hiermee uw oproeplogboek wissen of aanpassen."</string>
- <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Toestaan dat de app het oproeplogboek van uw telefoon aanpast, waaronder gegevens over inkomende en uitgaande oproepen. Schadelijke apps kunnen hiermee uw oproeplogboek wissen of aanpassen."</string>
+ <string name="permlab_readCallLog" msgid="3478133184624102739">"gesprekkenlijst lezen"</string>
+ <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Hiermee kan de app het gesprekkenlijst van uw tablet lezen, inclusief gegevens over inkomende en uitgaande oproepen. Met deze toestemming kunnen apps uw oproeploggegevens opslaan, en schadelijke apps kunnen logoproepgegevens zonder uw medeweten delen."</string>
+ <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Hiermee kan de app het gesprekkenlijst van uw telefoon lezen, inclusief gegevens over inkomende en uitgaande oproepen. Met deze toestemming kunnen apps uw oproeploggegevens opslaan, en schadelijke apps kunnen logoproepgegevens zonder uw medeweten delen."</string>
+ <string name="permlab_writeCallLog" msgid="8552045664743499354">"gesprekkenlijst schrijven"</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Toestaan dat de app het gesprekkenlijst van uw tablet aanpast, waaronder gegevens over inkomende en uitgaande oproepen. Schadelijke apps kunnen hiermee uw gesprekkenlijst wissen of aanpassen."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Toestaan dat de app het gesprekkenlijst van uw telefoon aanpast, waaronder gegevens over inkomende en uitgaande oproepen. Schadelijke apps kunnen hiermee uw gesprekkenlijst wissen of aanpassen."</string>
<string name="permlab_readProfile" msgid="4701889852612716678">"uw eigen contactkaart lezen"</string>
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Hiermee kan de app persoonlijke profielgegevens lezen die op uw apparaat zijn opgeslagen, zoals uw naam en contactgegevens. Dit betekent dat de app u kan identificeren en uw profielgegevens naar anderen kan verzenden."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"uw eigen contactkaart aanpassen"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"De app toestaan minder belangrijke functies van wifi-displays te beheren."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"audio-uitvoer vastleggen"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Hiermee kan de app audio-uitvoer vastleggen en verwerken."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectie van hotwords"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Hiermee kan de app audio opnemen voor het detecteren van hotwords. Het opnemen kan op de achtergrond plaatsvinden, maar voorkomt niet dat andere audio wordt opgenomen (bijvoorbeeld in Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"video-uitvoer vastleggen"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Hiermee kan de app video-uitvoer vastleggen en verwerken."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"beveiligde video-uitvoer vastleggen"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Hiermee kan de app voorkomen dat de tablet overschakelt naar de slaapmodus."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Hiermee kan de app voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infrarood verzenden"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Hiermee kan de app de infraroodzender van de tablet gebruiken."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Hiermee kan de app de infraroodzender van de telefoon gebruiken."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"tablet in- of uitschakelen"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"telefoon in- of uitschakelen"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Hiermee kan de app de tablet in- of uitschakelen."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Hiermee kan de houder de door de provider geleverde configuratie-app aanroepen. Nooit vereist voor normale apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"controleren op waarnemingen met betrekking tot netwerkomstandigheden"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Hiermee kan een app controleren op waarnemingen met betrekking tot netwerkomstandigheden. Nooit vereist voor normale apps."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"hotwordherkenning aanvragen"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Hiermee kan een app herkenning van hotwords aanvragen. Nooit vereist voor normale apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -848,7 +854,7 @@
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Patroon vergeten?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Account ontgrendelen"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Te veel patroonpogingen"</string>
- <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Als u wilt ontgrendelen, moet u zich aanmelden bij uw Google-account."</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Log in op uw Google-account om te ontgrendelen."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Gebruikersnaam (e-mail)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Wachtwoord"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inloggen"</string>
@@ -1163,7 +1169,7 @@
<item quantity="one" msgid="1634101450343277345">"Open wifi-netwerk beschikbaar"</item>
<item quantity="other" msgid="7915895323644292768">"Open wifi-netwerken beschikbaar"</item>
</plurals>
- <string name="wifi_available_sign_in" msgid="4029489716605255386">"Aanmelden bij wifi-netwerk"</string>
+ <string name="wifi_available_sign_in" msgid="4029489716605255386">"Inloggen op wifi-netwerk"</string>
<string name="network_available_sign_in" msgid="8495155593358054676">"Inloggen bij netwerk"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 6eacf2f..3196373 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zbyt wiele usuwanych <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pamięć tabletu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pamięć telefonu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieć może być monitorowana"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Przez nieznaną firmę zewnętrzną"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Przez <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcje tabletu"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opcje telefonu"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Zezwala aplikacji na zarządzanie niskopoziomowymi funkcjami wyświetlaczy Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"przechwyć wyjście audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Zezwala aplikacji na przechwytywanie i przekierowywanie wyjścia audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Wykrywanie słów-kluczy"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Umożliwia aplikacji przechwytywanie dźwięku w celu wykrywania słów-kluczy. Może się to odbywać w tle i nie uniemożliwia innego przechwytywania dźwięku (np. z kamery)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"przechwyć wyjście wideo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Zezwala aplikacji na przechwytywanie i przekierowywanie wyjścia wideo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"przechwyć bezpieczne wyjście wideo"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zapobieganie przejściu telefonu w stan uśpienia"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pozwala aplikacji na zapobieganie przechodzeniu tabletu do trybu uśpienia."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Pozwala aplikacji na zapobieganie przechodzeniu telefonu w tryb uśpienia."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"przesyłanie w podczerwieni"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Zezwala aplikacji na używanie nadajnika podczerwieni w tablecie."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Zezwala aplikacji na używanie nadajnika podczerwieni w telefonie."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"włączenie lub wyłączenie tabletu"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"włączanie lub wyłączanie telefonu"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Pozwala aplikacji na włączanie i wyłączanie tabletu."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Zezwala na wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"śledź stan sieci"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Pozwala aplikacji śledzić stan sieci. Nieprzeznaczone dla zwykłych aplikacji."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"żądaj rozpoznawania słów kluczowych"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Pozwala aplikacji prosić o rozpoznawanie słów kluczowych. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 40ab983..69884ab 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -100,7 +100,7 @@
<string name="roamingText9" msgid="7969296811355152491">"Roaming - Funcionalidade de Serviço Total"</string>
<string name="roamingText10" msgid="3992906999815316417">"Roaming - Funcionalidade de Serviço Parcial"</string>
<string name="roamingText11" msgid="4154476854426920970">"Faixa de Roaming activada"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Faixa de Roaming desactivada"</string>
+ <string name="roamingText12" msgid="1189071119992726320">"Faixa de Roaming desativada"</string>
<string name="roamingTextSearching" msgid="8360141885972279963">"A procurar Serviço"</string>
<string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
<string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -131,12 +131,17 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminações de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telemóvel está cheio. Elimine alguns ficheiros para libertar espaço."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorizada"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opções do tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opções do telefone"</string>
<string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Activar sem fios"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Desactivar sem fios"</string>
+ <string name="turn_on_radio" msgid="3912793092339962371">"Ativar sem fios"</string>
+ <string name="turn_off_radio" msgid="8198784949987062346">"Desativar sem fios"</string>
<string name="screen_lock" msgid="799094655496098153">"Bloqueio de ecrã"</string>
<string name="power_off" msgid="4266614107412865048">"Desligar"</string>
<string name="silent_mode_silent" msgid="319298163018473078">"Campainha desativada"</string>
@@ -237,7 +242,7 @@
<string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Poderão ser instalados scripts para tornar o conteúdo da aplicação mais acessível."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Observar o texto que escreve"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclui dados pessoais, como números de cartões de crédito e palavras-passe."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar ou modificar barra de estado"</string>
+ <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar barra de estado"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Permite à aplicação desativar a barra de estado ou adicionar e remover ícones do sistema."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"barra de estado"</string>
<string name="permdesc_statusBarService" msgid="716113660795976060">"Permite que a aplicação seja apresentada na barra de estado."</string>
@@ -289,7 +294,7 @@
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que a aplicação ative a depuração para outra aplicação. As aplicações maliciosas podem utilizar isto para eliminar outras aplicações."</string>
<string name="permlab_changeConfiguration" msgid="4162092185124234480">"alterar as definições de visualização do sistema"</string>
<string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Permite à aplicação alterar a configuração atual, como o local ou o tamanho global do tipo de letra."</string>
- <string name="permlab_enableCarMode" msgid="5684504058192921098">"activar modo de carro"</string>
+ <string name="permlab_enableCarMode" msgid="5684504058192921098">"ativar modo de carro"</string>
<string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permite que a aplicação ative o modo automóvel."</string>
<string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"fechar outras aplicações"</string>
<string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Permite que a aplicação termine processos em segundo plano de outras aplicações. Isto pode fazer com que outras aplicações deixem de funcionar."</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que a aplicação controle funcionalidades de baixo nível em visores Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar saída de áudio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite à aplicação capturar e redirecionar a saída de áudio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Deteção de Palavra de ativação"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite à aplicação capturar áudio para deteção da Palavra de ativação. A captura pode acontecer em segundo plano, mas não impede outras capturas de áudio (por exemplo com câmara de vídeo)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturar saída de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite à aplicação capturar e redirecionar a saída de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturar saída de vídeo segura"</string>
@@ -488,8 +495,8 @@
<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_cameraDisableTransmitLed" msgid="2651072630501126222">"desativar LED indicador de transmissão com a câmara em utilização"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que uma aplicação de sistema pré-instalada desative o LED indicador de utilização da câmara."</string>
- <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactivar tablet de forma permanente"</string>
- <string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar telefone de forma permanente"</string>
+ <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desativar tablet de forma permanente"</string>
+ <string name="permlab_brick" product="default" msgid="8337817093326370537">"desativar telefone de forma permanente"</string>
<string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Permite que a aplicação desative definitivamente todo o tablet. Esta ação é muito perigosa."</string>
<string name="permdesc_brick" product="default" msgid="5788903297627283099">"Permite que a aplicação desative definitivamente todo o telemóvel. Esta ação é muito perigosa."</string>
<string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"forçar reinício do tablet"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inactividade do telefone"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que a aplicação impeça o tablet de entrar no modo de suspensão."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que a aplicação impeça o telemóvel de entrar em inatividade."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmitir infravermelhos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite que a aplicação utilize o transmissor de infravermelhos do tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite que a aplicação utilize o transmissor de infravermelhos do telemóvel."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ligar ou desligar o tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ligar ou desligar o telefone"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que uma aplicação ligue ou desligue o tablet."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o titular invoque a aplicação de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ouvir observações sobre as condições da rede"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que uma aplicação ouça observações sobre as condições da rede. Nunca deverá ser necessário para aplicações normais."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"solicitar reconhecimento de palavras de ativação"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Permite que uma aplicação solicite o reconhecimento de palavras de ativação. Nunca deverá ser necessário para aplicações normais."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
@@ -1096,7 +1104,7 @@
<string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
<string name="loading" msgid="7933681260296021180">"A carregar…"</string>
<string name="capital_on" msgid="1544682755514494298">"Ativado"</string>
- <string name="capital_off" msgid="6815870386972805832">"Desactivar"</string>
+ <string name="capital_off" msgid="6815870386972805832">"Desativar"</string>
<string name="whichApplication" msgid="4533185947064773386">"Concluir ação utilizando"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Utilizar por predefinição para esta acção."</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Limpar a predefinição nas Definições do Sistema > Aplicações > Transferidas."</string>
@@ -1216,19 +1224,19 @@
<string name="usb_storage_title" msgid="5901459041398751495">"Ligado através de USB"</string>
<string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Ligou ao computador através de USB. Toque no botão abaixo se pretender copiar ficheiros entre o computador e a memória de armazenamento USB do Android."</string>
<string name="usb_storage_message" product="default" msgid="805351000446037811">"Ligou ao computador através de USB. Toque no botão abaixo se pretender copiar ficheiros entre o computador e o cartão SD do Android."</string>
- <string name="usb_storage_button_mount" msgid="1052259930369508235">"Activar armazenamento USB"</string>
+ <string name="usb_storage_button_mount" msgid="1052259930369508235">"Ativar armazenamento USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"Existe um problema ao utilizar a memória de armazenamento USB para o armazenamento em massa USB."</string>
<string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"Existe um problema ao utilizar o cartão SD para armazenamento em massa USB."</string>
<string name="usb_storage_notification_title" msgid="8175892554757216525">"Ligado através de USB"</string>
<string name="usb_storage_notification_message" msgid="939822783828183763">"Toque para copiar ficheiros para/do computador."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desactivar armazenamento USB"</string>
+ <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desativar armazenamento USB"</string>
<string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"Toque para desativar a memória de armazenamento USB."</string>
<string name="usb_storage_stop_title" msgid="660129851708775853">"O armazenamento USB está a ser utilizado"</string>
<string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"Antes de desativar a memória de armazenamento USB, desmonte (\"ejete\") a memória de armazenamento USB do Android do computador."</string>
<string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"Antes de desativar a memória de armazenamento USB, desmonte (\"ejete\") o cartão SD do Android do computador."</string>
- <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Desactivar armazenamento USB"</string>
+ <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Desativar armazenamento USB"</string>
<string name="usb_storage_stop_error_message" msgid="1970374898263063836">"Ocorreu um problema ao desativar a memória de armazenamento USB. Verifique se desinstalou o anfitrião USB e, em seguida, tente novamente."</string>
- <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Activar armazenamento USB"</string>
+ <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Ativar armazenamento USB"</string>
<string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Se ativar a memória de armazenamento USB, algumas aplicações que estiver a utilizar serão paradas e poderão ficar indisponíveis até desativar a memória de armazenamento USB."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"Operação USB sem êxito"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 6893b69..3a86f55 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Muitas exclusões de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telefone está cheio. Exclua alguns arquivos para liberar espaço."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorada"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por terceiros desconhecidos"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opções do tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opções do telefone"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite que o aplicativo controle recursos de baixo nível de monitores Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"capturar saída de áudio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que o aplicativo capture e redirecione a saída de áudio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detecção de hotwords"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite que o dispositivo capture áudio para a detecção de hotwords. A captura pode acontecer em segundo plano, mas não impede outras capturas de áudio (como por uma câmera de vídeo)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturar saída de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite que o aplicativo capture e redirecione a saída de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturar saída de vídeo segura"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inatividade do telefone"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que o aplicativo impeça o tablet de entrar no modo de inatividade."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que o aplicativo impeça o telefone de entrar no modo de inatividade."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmitir infravermelhos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite que o aplicativo use o transmissor infravermelho do tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite que o aplicativo use o transmissor infravermelho do telefone."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"ligar ou desligar o tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"ligar ou desligar o telefone"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que o aplicativo ative ou desative o tablet."</string>
@@ -655,10 +663,8 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o proprietário invoque o aplicativo de configuração fornecido pela operadora. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar observações nas condições da rede"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que o aplicativo detecte observações nas condições da rede. Não deve ser necessário para aplicativos comuns."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"solicitar reconhecimento de hotword"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Permite que o aplicativo solicite o reconhecimento de hotword. Não deve ser necessário para aplicativos comuns."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
- <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controle o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
+ <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitorar quantas vezes a senha foi digitada incorretamente ao desbloquear a tela e bloquear o tablet ou apagar todos os dados do tablet se a senha for digitada incorretamente muitas vezes."</string>
<string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitorar quantas vezes a senha foi digitada incorretamente ao desbloquear a tela e bloquear o telefone ou apagar todos os dados do telefone se a senha for digitada incorretamente muitas vezes."</string>
@@ -668,7 +674,7 @@
<string name="policydesc_forceLock" msgid="1141797588403827138">"Controle como e quando a tela é bloqueada."</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Apagar todos os dados"</string>
<string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Apague os dados do tablet sem aviso redefinindo a configuração original."</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Apague os dados do telefone sem aviso redefinindo a configuração original."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Apagar os dados do telefone sem aviso redefinindo a configuração original."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configura o proxy global do dispositivo para ser usado enquanto a política estiver ativada. Somente o primeiro administrador do dispositivo pode configurar um verdadeiro proxy global."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"Definir val. da senha de bloqueio"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index fd717b9..c4b5e5b 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -158,6 +158,12 @@
<skip />
<!-- no translation found for low_memory (3475999286680000541) -->
<skip />
+ <!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Jau"</string>
<!-- no translation found for power_dialog (8545351420865202853) -->
<skip />
@@ -781,6 +787,10 @@
<skip />
<!-- no translation found for permdesc_captureAudioOutput (6210597754212208853) -->
<skip />
+ <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
+ <skip />
+ <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
+ <skip />
<!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
<skip />
<!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
@@ -900,6 +910,12 @@
<skip />
<!-- no translation found for permdesc_wakeLock (8559100677372928754) -->
<skip />
+ <!-- no translation found for permlab_transmitIr (7545858504238530105) -->
+ <skip />
+ <!-- no translation found for permdesc_transmitIr (5358308854306529170) -->
+ <skip />
+ <!-- no translation found for permdesc_transmitIr (7957763745020300725) -->
+ <skip />
<!-- no translation found for permlab_devicePower (2787034722616350417) -->
<skip />
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"metter en/ord funcziun l\'apparat"</string>
@@ -1108,10 +1124,6 @@
<skip />
<!-- no translation found for permdesc_accessNetworkConditions (6899102075825272211) -->
<skip />
- <!-- no translation found for permlab_hotwordRecognition (3225080408746361313) -->
- <skip />
- <!-- no translation found for permdesc_hotwordRecognition (3716741260195364252) -->
- <skip />
<!-- no translation found for policylab_limitPassword (4497420728857585791) -->
<skip />
<!-- no translation found for policydesc_limitPassword (3252114203919510394) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 38015ba..9842414 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ştergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rețeaua poate fi monitorizată"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opţiuni tablet PC"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opţiuni telefon"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Permite aplicaţiei să controleze funcţiile de nivel redus ale afişajelor Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"să intercepteze ieșirea audio"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite aplicației să intercepteze și să redirecționeze ieșirea audio."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"detectarea expresiei de activare"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Activează captarea semnalului audio de către aplicație pentru detectarea expresiei de activare. Captarea poate avea loc în fundal, dar nu împiedică altă captare audio (de ex., cameră video)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"să intercepteze ieșirea video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite aplicației să intercepteze și să redirecționeze ieșirea video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"să intercepteze ieșirea video securizată"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite aplicaţiei să împiedice intrarea tabletei în stare de repaus."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite aplicaţiei să împiedice intrarea telefonului în stare de repaus."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"transmisie prin infraroșii"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Permite aplicației să utilizeze transmițătorul prin infraroșii al tabletei."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Permite aplicației să utilizeze transmițătorul prin infraroșii al telefonului."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"pornire sau oprire computer tablet PC"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"telefon pornit sau oprit"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite aplicaţiei să pornească sau să oprească tableta."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite proprietarului să apeleze aplicația de configurare furnizată de operator. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascultă observații despre starea rețelei"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite unei aplicații să asculte observații despre starea rețelei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"solicitare de recunoaștere a unei expresii de activare"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Permite unei aplicații să solicite recunoașterea unei expresii de activare. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 63f9012..e96a40d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Слишком много удалений <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Память планшетного ПК заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Память телефона заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Действия в сети могут отслеживаться"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Настройки планшетного ПК"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Параметры телефона"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Приложение сможет управлять низкоуровневыми функциями экранов, подключенных через Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"захват аудиосигнала"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Приложение сможет захватывать и перенаправлять аудиосигнал."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"распознавать голосовые команды"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Приложение сможет анализировать звук для распознавания голосовых команд. Этот процесс выполняется в фоновом режиме и не мешает другим операциям (например, записи видеоролика)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"захват видеосигнала"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Приложение сможет захватывать и перенаправлять видеосигнал."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"захват защищенного видеосигнала"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Отключение спящего режима"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Приложение сможет запрещать перевод планшетного ПК в спящий режим."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Приложение сможет запрещать перевод телефона в спящий режим."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"использовать инфракрасный передатчик"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Приложение сможет использовать инфракрасный передатчик планшетного ПК."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Приложение сможет использовать инфракрасный передатчик телефона."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Включение/выключение планшета"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Включение/выключение телефона"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Приложение сможет включать и выключать планшетный ПК."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Владелец сможет запускать приложение настроек, предоставленное оператором. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Использование данных о состоянии сети"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Приложение сможет использовать данные о состоянии сети. Это разрешение обычно используется только специальными приложениями."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"запрашивать распознавание голосовых команд"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Приложение сможет запрашивать распознавание голосовых команд. Это разрешение обычно используется только специальными приложениями."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d1f8a7f..d944031 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Príliš veľa odstránených položiek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Ukladací priestor tabletu je plný. Odstráňte niektoré súbory a uvoľnite miesto."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pamäť telefónu je plná. Odstráňte niektoré súbory a uvoľnite miesto."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieť môže byť monitorovaná"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Možnosti tabletu"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Možnosti telefónu"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Umožňuje aplikácii ovládať základné funkcie displejov cez siete Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"zachytiť výstup zvuku"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Umožňuje aplikácii zachytiť a presmerovať výstup zvuku."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Rozpoznanie kľúčových slov"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Umožňuje aplikácii zaznamenať zvuk s cieľom rozpoznať kľúčové slová. Záznam sa môže uskutočniť na pozadí a nebráni inému zaznamenávaniu zvuku (napríklad videokamerou)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"zachytiť výstup videa"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Umožňuje aplikácii zachytiť a presmerovať výstup videa."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"zachytiť zabezpečený výstup videa"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zabránenie prechodu telefónu do režimu spánku"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikácii zabrániť prechodu tabletu do režimu spánku."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Umožňuje aplikácii zabrániť prechodu telefónu do režimu spánku."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"infračervený prenos"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Umožňuje aplikácii používať infračervený vysielač tabletu."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Umožňuje aplikácii používať infračervený vysielač telefónu."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"zapnutie a vypnutie tabletu"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"zapnutie a vypnutie telefónu"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Umožňuje aplikácii zapnúť a vypnúť tablet."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje držiteľovi vyvolať aplikáciu pre konfiguráciu poskytnutú operátorom. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"zachytávať informácie o stave siete"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikácii zachytávať informácie o stave siete. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"požiadavka rozpoznania kľúčových slov"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Umožňuje aplikácii požadovať rozpoznanie kľúčových slov. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5a5e6cd..b047c1a9 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Preveč izbrisov vsebine <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pomnilnik tabličnega računalnika je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pomnilnik telefona je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Omrežje je lahko nadzorovano"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Neznana tretja oseba"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Nadzira: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Jaz"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Možnosti tabličnega računalnika"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Možnosti telefona"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Omogoča aplikaciji nadzor osnovnih funkcij zaslonov Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"zajem avdioizhoda"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Omogoči aplikaciji, da zajame in preusmeri avdioizhod."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Zaznavanje sprožilnih besed"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Aplikaciji dovoljuje snemanje zvoka za zaznavanje sprožilnih besed. Snemanje je možno tudi v ozadju, ne preprečuje pa drugega snemanja zvoka (npr. z videokamero)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"zajem videoizhoda"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Omogoči aplikaciji, da zajame in preusmeri videoizhod."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"zajem varnega videoizhoda"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"preprečevanje prehoda v stanje pripravljenosti telefona"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Omogoča, da program prepreči prehod tabličnega računalnika v stanje pripravljenosti."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Programu omogoča, da v telefonu prepreči prehod v stanje pripravljenosti."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"prenašanje z infrardečim oddajnikom"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Aplikaciji dovoljuje uporabo infrardečega oddajnika tabličnega računalnika."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Aplikaciji dovoljuje uporabo infrardečega oddajnika telefona."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"vklop ali izklop tabličnega računalnika"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"vklop ali izklop telefona"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Programu omogoča vklop ali izklop tabličnega računalnika."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lastniku omogoča sproženje operaterjeve aplikacije za konfiguracijo. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"spremljanje razmer v omrežju"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Aplikaciji omogoča spremljanje razmer v omrežju. Pri navadnih aplikacijah to ne bi smelo biti potrebno."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"zahteva za prepoznavanje sprožilne besede"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Aplikaciji omogoča, da zahteva prepoznavanje sprožilnih besed. Za običajne aplikacije to nikoli ni potrebno."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4ad756a..7480afd 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Превише <xliff:g id="CONTENT_TYPE">%s</xliff:g> избрисаних ставки."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Меморија таблета је пуна! Избришите неке датотеке да бисте ослободили простор."</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_managed" msgid="4030263497686867141">"Од стране <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ја"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Опције за таблет"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Опције телефона"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Дозвољава апликацији да контролише функције Wi-Fi екрана ниског нивоа."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"снимање аудио садржаја"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Дозвољава апликацији да снима и преусмерава аудио садржај."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Откривање актуелних речи"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Дозвољава апликацији да снима звук за откривање актуелних речи. Снимање може да се дешава у позадини, али не спречава друга снимања звука (нпр. камкордер)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"снимање видео садржаја"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Дозвољава апликацији да снима и преусмерава видео садржај."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"снимање безбедног видео садржаја"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"спречавање преласка телефона у стање спавања"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозвољава апликацији да спречи таблет да пређе у стање спавања."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дозвољава апликацији да спречи телефон да пређе у стање спавања."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"пренос инфрацрвених зрака"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Дозвољава апликацији да користи одашиљач инфрацрвених зрака таблета."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Дозвољава апликацији да користи одашиљач инфрацрвених зрака телефона."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"укључивање или искључивање таблета"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"укључивање или искључивање телефона"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дозвољава апликацији да укључује или искључује таблет."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозвољава власнику да позива апликацију са конфигурацијом коју одређује оператер. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"праћење података о условима на мрежи"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозвољава апликацији да прати податке о условима на мрежи. Не би никада требало да буде потребно за нормалне апликације."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"захтевање препознавања актуелних речи"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Дозвољава апликацији да захтева препознавање актуелних речи. Уобичајене апликације никада не би требало да је користе."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 6071995..2c04831 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"För många <xliff:g id="CONTENT_TYPE">%s</xliff:g>-borttagningar."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pekdatorns lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Mobilens lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nätverket kan vara övervakat"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en okänd tredje part"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Av <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Jag"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Alternativ för surfplattan"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonalternativ"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Tillåter att appen kontrollerar grundläggande funktioner för Wi-Fi-skärmar."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"fånga upp ljudutgång"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Tillåt att appen fångar upp och omdirigerar ljudutgången."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Kommandoordsidentifiering"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Tillåter att appen spelar in ljud för att upptäcka kommandoord. Inspelningen kan pågå i bakgrunden utan att hindra andra ljudinspelningar (t.ex. med videokamera)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"fånga upp videoutgång"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Tillåt att appen fångar upp och omdirigerar videoutgången."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"fånga upp säker videoutgång"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"förhindra att telefonen sätts i viloläge"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillåter att appen förhindrar att surfplattan går in i viloläge."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Tillåter att appen förhindrar att mobilen går in i viloläge."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"tillåt IR-sändning"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Tillåter att appen använder surfplattans IR-sändare."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Tillåter att appen använder mobilens IR-sändare."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"slå på eller stänga av surfplattan"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"sätta på eller stänga av telefonen"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Tillåter att appen slår på eller stänger av surfplattan."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Innehavaren tillåts att anropa konfigurationsappen från operatören. Ska inte behövas för vanliga appar."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lyssna efter information om nätverksförhållanden"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillåter att appen lyssnar efter information om nätverksförhållanden. Vanliga appar bör aldrig behöva den här behörigheten."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"begär identifiering av kommandoord"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Tillåter att en app begär identifiering av kommandoord. Bör aldrig vara nödvändigt för normala appar."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8774c71..2049364 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Ufutaji mwingi sana <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Hifadhi ya kompyuta kibao imejaa. Futa baadhi ya faili ili kupata nafasi."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Hifadhi ya simu imejaa. Futa baadhi ya faili ili uweze kupata nafasi."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mtandao unaweza kufuatiliwa"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Na mtu mwingine asiyejulikana"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Na <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Mimi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Chaguo za kompyuta ndogo"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Machaguo ya simu"</string>
@@ -447,7 +450,7 @@
<string name="permlab_writeProfile" msgid="907793628777397643">"rekebisha kadi yako mwenyewe ya mawasiliano"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Inaruhusu programu kubadilisha au kuongeza taarifa ya maelezo mafupi ya kibinafsi yaliyohifadhiwa kwenye kifaa chako, kama vile jina lako na taarifa ya anwani. Hii inamaanisha kuwa programu inaweza kukutambua na inaweza kutuma taarifa ya maelezo yako mafupi kwa wengine."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"soma mipasho yako wa kijamii"</string>
- <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Huruhusu programu kufikia na kupatanisha masasisho ya kijamii kutoka kwa marafiki zako. Kuwa makini wakati unashiriki taarifa -- hii huruhusu programu kusoma mawasiliano kati yako na marafiki zako kwenye mitandao ya jamii, bila kujali usiri. Kumbuka: idhini hii haiwezi kutekelezwa kwenye mitandao yote ya jamii."</string>
+ <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Huruhusu programu kufikia na kupatanisha masasisho ya kijamii kutoka kwa marafiki zako. Kuwa makini wakati unashiriki taarifa -- hii huruhusu programu kusoma mawasiliano kati yako na marafiki zako kwenye mitandao jamii, bila kujali usiri. Kumbuka: idhini hii haiwezi kutekelezwa kwenye mitandao yote ya jamii."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"andika kwa mipasho yako wa kijamii"</string>
<string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"Huruhusu programu kuonyesha masasisho ya kijamii kutoka kwa marafiki zako. Kuwa makini wakati unashiriki taarifa -- hii inaruhusu programu kutoa ujumbe unaoweza kuonekana kuwa unatoka kwa rafiki. Kumbuka: idhini hii huenda usitekelezwe kwenye mitandao yote ya jamii."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"soma matukio ya kalenda pamoja na maelezo ya siri"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Inaruhusu programu kudhibiti vipengele vya kiwango cha chini vya maonyesho ya Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"nasa sauti"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Inaruhusu programu kunasa na kuelekeza sauti kwingine."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Kutambua neno tekelezi"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Inaruhusu programu kunasa sauti kwa ajili ya utambuzi wa Neno tekelezi. Kunasa kunaweza kukafanyika chinichini lakini hakutazuia unasaji mwingine wa sauti (kwa mfano Kamkoda)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"nasa sauti ya video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Inaruhusu programu kunasa na kuelekeza video kwingine."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"nasa sauti ya video kwa usalama"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zuia simu dhidi ya kulala"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Inaruhusu programu kuzuia kompyuta kibao kwenda kulala."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Inaruhusu programu kuzuia simu isiende kulala."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"sambaza infrared"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Inaruhusu programu kutumia transmita ya infrared ya kompyuta kibao."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Inaruhusu programu kutumia transmita ya infrared ya simu."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Washa au zima kompyuta kibao"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"washa au zima simu"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Inaruhusu programu kuwasha au kuzima kompyuta kibao."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Inaruhusu kishikiliaji kuomba programu ya usakinishaji inayotolewa na mto huduma. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"sikiliza matukio katika hali za mtandao"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Huruhusu programu kusikiliza matukio katika hali za mtandao. Haipaswi kuhitajika kamwe kwa programu za kawaida."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"kuomba utambuzi wa neno tekelezi"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Huruhusu programu kuomba utambuzi wa neno tekelezi. Haipaswi kuhitajika kamwe kwa programu za kawaida."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Weka kanuni za nenosiri"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Dhibiti urefu na vibambo vinavyoruhusiwa katika manenosiri ya kufungua skrini."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Chunguza majaribio ya kutofun gua skrini"</string>
diff --git a/core/res/res/values-sw600dp-port/refs.xml b/core/res/res/values-sw600dp-port/refs.xml
deleted file mode 100644
index cda38cf..0000000
--- a/core/res/res/values-sw600dp-port/refs.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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>
- <item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources>
\ No newline at end of file
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 245b67e..a0b0255 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"มีการลบ <xliff:g id="CONTENT_TYPE">%s</xliff:g> มากเกินไป"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ที่จัดเก็บข้อมูลของแท็บเล็ตเต็ม ลบไฟล์บางไฟล์เพื่อเพิ่มพื้นที่ว่าง"</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_managed" msgid="4030263497686867141">"โดย <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"ฉัน"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"ตัวเลือกของแท็บเล็ต"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"ตัวเลือกโทรศัพท์"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"อนุญาตให้แอปควบคุมคุณลักษณะต่างๆ ในระดับล่างของการแสดงผลด้วย WiFi"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"บันทึกเอาต์พุตเสียง"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"อนุญาตให้แอปบันทึกและเปลี่ยนเส้นทางเอาต์พุตเสียง"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"การตรวจหาคำที่นิยม"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"อนุญาตให้แอปเก็บเสียงสำหรับการตรวจหาคำที่นิยม การเก็บเสียงสามารถดำเนินการอยู่ในพื้นหลัง แต่ไม่เป็นการป้องกันการเก็บเสียงอื่นๆ (เช่น กล้องวิดีโอ)"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"บันทึกเอาต์พุตวิดีโอ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"อนุญาตให้แอปบันทึกและเปลี่ยนเส้นทางเอาต์พุตวิดีโอ"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"บันทึกเอาต์พุตเสียงที่ปลอดภัย"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ป้องกันไม่ให้โทรศัพท์เข้าโหมดสลีป"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"อนุญาตให้แอปพลิเคชันป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"อนุญาตให้แอปพลิเคชันป้องกันไม่ให้โทรศัพท์เข้าสู่โหมดสลีป"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"ส่งสัญญาณอินฟราเรด"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"อนุญาตให้แอปใช้ตัวส่งสัญญาณอินฟราเรดของแท็บเล็ต"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"อนุญาตให้แอปใช้ตัวส่งสัญญาณอินฟราเรดของโทรศัพท์"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"เปิดหรือปิดเครื่องแท็บเล็ต"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"เปิดหรือปิดโทรศัพท์"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"อนุญาตให้แอปพลิเคชันเปิดหรือปิดแท็บเล็ต"</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"อนุญาตให้ผู้ใช้สามารถเรียกใช้แอปการกำหนดค่าของผู้ให้บริการ ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"อนุญาตให้แอปพลิเคชันฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย ไม่จำเป็นสำหรับแอปปกติ"</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"ขอการจดจำเสียงคำที่นิยม"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"อนุญาตให้แอปพลิเคชันขอการจดจำเสียงคำที่นิยม ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 9a410d7..5b06737 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Masyadong maraming pagtanggal ng <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Puno na ang storage ng tablet. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Puno na ang storage ng telepono. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Maaaring sinusubaybayan ang network"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ng isang di-kilalang third party"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Ng <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ako"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Mga pagpipilian sa tablet"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Mga pagpipilian sa telepono"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Pinapayagan ang app na magkontrol ng mga tampok sa mababang antas ng mga dispay ng Wifi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"kumuha ng audio output"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Pinapayagan ang app na kumuha at mag-redirect ng audio output."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Paghahanap ng hotword"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Nagbibigay-daan sa app na kumuha ng audio na paghahanapan ng Hotword. Maaaring maisagawa sa background ang pagkuha, ngunit hindi nito pipigilan ang iba pang pagkuha ng audio (hal. Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"kumuha ng video output"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Pinapayagan ang app na kumuha at mag-redirect ng video output."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"kumuha ng secure na video output"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"pigilan ang telepono mula sa paghinto"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pinapayagan ang app na pigilan ang tablet mula sa pag-sleep."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Pinapayagan ang app na pigilan ang telepono mula sa pag-sleep."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"magpadala gamit ang infrared"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Nagbibigay-daan sa app na gamitin ang infrared transmitter ng tablet."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Nagbibigay-daan sa app na gamitin ang infrared transmitter ng telepono."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"i-on o i-off ang power tablet"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"i-on o i-off ang telepono"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Pinapayagan ang app na i-on o i-off ang tablet."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Nagbibigay-daan sa may-ari na paganahin ang app ng configuration na ibinigay ng carrier. Hindi dapat kailanganin para sa normal na apps kahit kailan."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"makinig sa mga obserbasyon sa mga kundisyon ng network"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Nagbibigay-daan sa isang application na makinig sa mga obserbasyon sa mga kundisyon ng network. Dapat na hindi kailanman kakailanganin para sa normal na apps."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"humiling ng hotword recognition"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Pinapayagan ang isang application na humiling ng hotword recognition. Hindi dapat kailanganin kailanman para sa normal na apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 13767a2..14f98d7 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Çok fazla <xliff:g id="CONTENT_TYPE">%s</xliff:g> silme var."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletin depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonun depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ağ izlenebilir"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Ben"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet seçenekleri"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefon seçenekleri"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Uygulamaya kablosuz ekranların alt düzey özelliklerini kontrol etme izni verir."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ses çıkışını yakala"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Uygulamaya, ses çıkışını yakalayıp yönlendirme izni verir."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Önemli kelime algılama"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Uygulamaya, Özel kelime algılamak için ses yakalama izni verir. Ses yakalama işlemi arka planda yapılabilir, ancak diğer ses yakalama işlemlerini (ör. kameranın ses kaydını) engellemez."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"video çıkışını yakala"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Uygulamaya, video çıkışını yakalayıp yönlendirme izni verir."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"güvenli video çıkışını yakala"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefonun uykuya geçmesini önleme"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Uygulamaya, tabletin uykuya geçmesini önleme izni verir."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Uygulamaya, telefonun uykuya geçmesini önleme izni verir."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"kızı ötesi iletme"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Uygulamaya, tabletin kızıl ötesi vericisini kullanma izni verir."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Uygulamaya, telefonunun kızıl ötesi vericisini kullanma izni verir."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"tableti aç veya kapat"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"telefonu aç veya kapat"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Uygulamaya, tabletinizi açma veya kapatma izni verir."</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"İzin sahibine, operatör tarafından sağlanan yapılandırma uygulamasını çalıştırma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ağ koşullarındaki gözlemleri dinle"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Bir uygulamaya, ağ koşullarındaki gözlemleri dinleme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"özel kelime tanıma isteğinde bulunma"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Bir uygulamaya, özel kelime tanıma isteğine erişim izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index c0b0686..3ff9fd9 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Забагато видалень <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Пам’ять планшетного ПК заповнено. Видаліть якісь файли, щоб звільнити місце."</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_managed" msgid="4030263497686867141">"Доменом <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Парам. пристрою"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Параметри тел."</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Дозволяє програмі керувати низькорівневими функціями екранів Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"отримувати доступ до аудіовиходу"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Дозволяє програмі отримувати доступ до аудіовиходу й переспрямовувати його."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"виявляти команди швидкого запуску"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Дозволяє програмі записувати аудіо для виявлення команд швидкого запуску. Запис відбуватиметься у фоновому режимі й не перешкоджатиме запису іншого аудіо (напр., з відеокамери)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"отримувати доступ до відеовиходу"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Дозволяє програмі отримувати доступ до відеовиходу й переспрямовувати його."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"отримувати доступ до захищеного відеовиходу"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"недоп. перехід тел. в реж. сну"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозволяє програмі не допускати перехід планшетного ПК у режим сну."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дозволяє програмі не допускати перехід телефону в режим сну."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"передавати в інфрачервоному діапазоні"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Дозволяє програмі використовувати інфрачервоний передавач планшета."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Дозволяє програмі використовувати інфрачервоний передавач телефону."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"увімк. чи вимк. пристрій"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"вмик. чи вимик. телефон"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дозволяє програмі вимикати чи вимикати планшетний ПК."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозволяє власнику викликати надану оператором програму конфігурації. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"прослуховувати дані спостережень за станом мережі"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозволяє програмі прослуховувати дані спостережень за станом мережі. Ніколи не застосовується для звичайних програм."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"запитувати розпізнавання команд швидкого запуску"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Дозволяє програмі надсилати запит на розпізнавання команд швидкого запуску. Ніколи не застосовується для звичайних програм."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index bdffda0..26e3f6e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Quá nhiều lần xóa <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Bộ nhớ máy tính bảng đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Bộ nhớ điện thoại đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mạng có thể được giám sát"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Bởi một bên thứ ba không xác định"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Bởi <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Tôi"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tùy chọn máy tính bảng"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Tùy chọn điện thoại"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Cho phép ứng dụng kiểm soát các tính năng cấp thấp của màn hình Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"thu thập dữ liệu đầu ra âm thanh"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Cho phép ứng dụng thu thập và chuyển hướng dữ liệu đầu ra âm thanh."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Phát hiện từ nóng"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Cho phép ứng dụng thu thập dữ liệu âm thanh để phát hiện từ nóng. Quá trình thu thập này có thể diễn ra trong nền nhưng không ngăn các hoạt động thu thập dữ liệu âm thanh khác (ví dụ: máy quay video)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"thu thập dữ liệu đầu ra video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Cho phép ứng dụng thu thập và chuyển hướng dữ liệu đầu ra video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"thu thập dữ liệu đầu ra video an toàn"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ngăn điện thoại chuyển sang chế độ ngủ"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Cho phép ứng dụng ngăn máy tính bảng chuyển sang chế độ ngủ."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Cho phép ứng dụng ngăn điện thoại chuyển sang chế độ ngủ."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"phát hồng ngoại"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Cho phép ứng dụng sử dụng bộ phát hồng ngoại của máy tính bảng."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Cho phép ứng dụng sử dụng bộ phát hồng ngoại của điện thoại."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"bật hoặc tắt máy tính bảng"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"bật hoặc tắt điện thoại"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Cho phép ứng dụng bật hoặc tắt máy tính bảng."</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Cho phép chủ sở hữu gọi ra ứng dụng cấu hình do nhà cung cấp dịch vụ cung cấp. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"quan sát các điều kiện mạng"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Cho phép ứng dụng quan sát các điều kiện mạng. Không bao giờ cần cho ứng dụng thông thường."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"yêu cầu công nhận từ nóng"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Cho phép ứng dụng yêu cầu công nhận từ nóng. Không bao giờ cần cho ứng dụng thông thường."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kiểm soát độ dài và ký tự được phép trong mật khẩu mở khóa màn hình."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b8aca7b..b250f14 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -131,6 +131,11 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"太多<xliff:g id="CONTENT_TYPE">%s</xliff:g>删除项。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板电脑存储空间已满。请删除一些文件以腾出空间。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手机存储空间已满。请删除一些文件以腾出空间。"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"网络可能会受到监控"</string>
+ <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+ <skip />
+ <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"我"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"平板电脑选项"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"手机选项"</string>
@@ -476,6 +481,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允许应用控制 WLAN 显示设备的基础功能。"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"捕获音频输出"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允许该应用捕获和重定向音频输出。"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"关键词检测"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允许应用针对关键词检测捕获音频。捕获操作会在后台进行,但不会禁止使用其他音频捕获工具(例如摄像机)。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"捕获视频输出"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允许该应用捕获和重定向视频输出。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"捕获安全视频输出"</string>
@@ -543,6 +550,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手机休眠"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允许应用阻止平板电脑进入休眠状态。"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"允许应用阻止手机进入休眠状态。"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"发射红外线"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"允许应用使用平板电脑的红外线发射器。"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"允许应用使用手机的红外线发射器。"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"打开或关闭平板电脑"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"开机或关机"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"允许应用打开或关闭平板电脑。"</string>
@@ -637,7 +647,7 @@
<string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"允许应用访问所有用户的外部存储设备。"</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"访问缓存文件系统"</string>
<string name="permdesc_cache_filesystem" msgid="5578967642265550955">"允许应用读取和写入缓存文件系统。"</string>
- <string name="permlab_use_sip" msgid="5986952362795870502">"拨打/接听互联网通话"</string>
+ <string name="permlab_use_sip" msgid="5986952362795870502">"拨打/接听互联网电话"</string>
<string name="permdesc_use_sip" msgid="4717632000062674294">"允许应用使用 SIP 服务拨打/接听互联网电话。"</string>
<string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"读取网络使用情况历史记录"</string>
<string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"允许应用读取特定网络和应用的网络使用情况历史记录。"</string>
@@ -655,8 +665,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允许应用调用运营商提供的配置应用。普通应用绝不需要此权限。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"监听网络状况的观测信息"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允许应用监听网络状况的观测信息。普通应用绝不需要此权限。"</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"请求识别关键词"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"允许应用请求识别关键词。普通应用绝不需要此权限。"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
@@ -682,7 +690,7 @@
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"住宅"</item>
<item msgid="869923650527136615">"手机"</item>
- <item msgid="7897544654242874543">"单位电话"</item>
+ <item msgid="7897544654242874543">"单位"</item>
<item msgid="1103601433382158155">"单位传真"</item>
<item msgid="1735177144948329370">"住宅传真"</item>
<item msgid="603878674477207394">"寻呼机"</item>
@@ -690,8 +698,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>
@@ -748,8 +756,8 @@
<string name="eventTypeAnniversary" msgid="3876779744518284000">"周年纪念日"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"其他"</string>
<string name="emailTypeCustom" msgid="8525960257804213846">"自定义"</string>
- <string name="emailTypeHome" msgid="449227236140433919">"家用"</string>
- <string name="emailTypeWork" msgid="3548058059601149973">"单位"</string>
+ <string name="emailTypeHome" msgid="449227236140433919">"个人"</string>
+ <string name="emailTypeWork" msgid="3548058059601149973">"工作"</string>
<string name="emailTypeOther" msgid="2923008695272639549">"其他"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"手机"</string>
<string name="postalTypeCustom" msgid="8903206903060479902">"自定义"</string>
@@ -1169,10 +1177,10 @@
<skip />
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到 WLAN"</string>
<string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互联网连接状况不佳。"</string>
- <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WLAN Direct"</string>
- <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动 WLAN Direct。此操作将会关闭 WLAN 客户端/热点。"</string>
- <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"无法启动 WLAN Direct。"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用 WLAN Direct"</string>
+ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WLAN 直连"</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动 WLAN 直连。此操作将会关闭 WLAN 客户端/热点。"</string>
+ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"无法启动 WLAN 直连。"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用 WLAN 直连"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"通过触摸进行设置"</string>
<string name="accept" msgid="1645267259272829559">"接受"</string>
<string name="decline" msgid="2112225451706137894">"拒绝"</string>
@@ -1422,9 +1430,9 @@
<string name="extract_edit_menu_button" msgid="8940478730496610137">"修改"</string>
<string name="data_usage_warning_title" msgid="1955638862122232342">"流量使用警告"</string>
<string name="data_usage_warning_body" msgid="2814673551471969954">"触摸可查看使用情况和设置。"</string>
- <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G-3G 数据已停用"</string>
- <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G 数据已停用"</string>
- <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"移动数据已停用"</string>
+ <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G-3G 数据网络已停用"</string>
+ <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G 数据网络已停用"</string>
+ <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"移动数据网络已停用"</string>
<string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"WLAN 数据网络已停用"</string>
<string name="data_usage_limit_body" msgid="3317964706973601386">"触摸可启用。"</string>
<string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"已超出 2G-3G 数据流量限制"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 925d826..e924d01 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</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_managed" msgid="4030263497686867141">"受到 <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> 監控"</string>
<string name="me" msgid="6545696007631404292">"我本人"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"平板電腦選項"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"手機選項"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允許應用程式控制 WiFi Display 的低階功能。"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"擷取音頻輸出"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允許應用程式擷取及重新導向音頻輸出。"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"啟動字詞偵測"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允許應用程式擷取啟動字詞偵測的音頻。擷取操作可以在背景執行,但並未阻止其他音頻擷取 (例如攝錄機)。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"擷取視頻輸出"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允許應用程式擷取及重新導向視頻輸出。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"擷取安全視頻輸出"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入休眠狀態"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"允許應用程式防止手機進入休眠狀態。"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"傳送紅外線"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"允許應用程式使用平板電腦的紅外線傳送器。"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"允許應用程式使用手機的紅外線傳送器。"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"開啟或關閉平板電腦"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"開啟或關閉手機"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"允許應用程式開啟或關閉平板電腦。"</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式調用流動網絡供應商提供的設定應用程式 (不建議一般應用程式使用)。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽對網絡狀況的觀察"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽對網絡狀況的觀察 (不建議一般應用程式使用)。"</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"要求識別啟動字詞"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"允許應用程式要求識別啟動字詞 (不建議一般應用程式使用)。"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解鎖密碼所允許的長度和字元。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"監控屏幕解鎖嘗試次數"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index dd3d934..7be248f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以釋放出可用空間。"</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_managed" msgid="4030263497686867141">"受到 <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> 監控"</string>
<string name="me" msgid="6545696007631404292">"我"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"平板電腦選項"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"電話選項"</string>
@@ -476,6 +479,8 @@
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允許應用程式控制 Wi-Fi 顯示裝置的低階功能。"</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"擷取音訊輸出"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允許應用程式擷取及重新導向音訊輸出。"</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"熱門字詞偵測"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允許應用程式針對熱門字詞偵測擷取音訊。擷取作業可在背景執行,但並未禁止使用其他音訊擷取工具 (例如攝錄影機)。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"擷取視訊輸出"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允許應用程式擷取及重新導向視訊輸出。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"擷取安全視訊輸出"</string>
@@ -543,6 +548,9 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入待命狀態"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"允許應用程式防止手機進入休眠狀態。"</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"傳送紅外線"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"允許應用程式使用平板電腦的紅外線傳送器。"</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"允許應用程式使用手機的紅外線傳送器。"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"開啟或關閉平板電腦"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"開啟或關閉電源"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"允許應用程式開啟或關閉平板電腦。"</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式叫用行動通訊業者提供的設定應用程式 (一般應用程式並不需要)。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽網路狀況觀察資訊"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽網路狀況觀察資訊 (一般應用程式並不需要)。"</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"要求識別熱門字詞"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"允許應用程式要求識別熱門字詞 (一般應用程式並不需要)。"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
@@ -674,7 +680,7 @@
<string name="policylab_expirePassword" msgid="885279151847254056">"設定螢幕上鎖密碼到期日"</string>
<string name="policydesc_expirePassword" msgid="1729725226314691591">"控制螢幕上鎖密碼的變更頻率。"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"設定儲存裝置加密"</string>
- <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"必須為儲存的應用程式資料加密。"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"必須為儲存的應用程式資料進行加密。"</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"停用相機"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"禁止使用所有裝置相機。"</string>
<string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"停用鍵盤保護框上的功能"</string>
@@ -724,7 +730,7 @@
</string-array>
<string name="phoneTypeCustom" msgid="1644738059053355820">"自訂"</string>
<string name="phoneTypeHome" msgid="2570923463033985887">"住家"</string>
- <string name="phoneTypeMobile" msgid="6501463557754751037">"行動裝置"</string>
+ <string name="phoneTypeMobile" msgid="6501463557754751037">"手機"</string>
<string name="phoneTypeWork" msgid="8863939667059911633">"公司"</string>
<string name="phoneTypeFaxWork" msgid="3517792160008890912">"公司傳真"</string>
<string name="phoneTypeFaxHome" msgid="2067265972322971467">"住家傳真"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c79f31d..f96b062 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -131,6 +131,9 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Kunokususa <xliff:g id="CONTENT_TYPE">%s</xliff:g> okuningi kakhulu."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Isilondolozi sethebhulethi sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Isilondolozi sefoni sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Inethiwekhi ingase inganyelwe"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ngenkampani yangaphandle engaziwa"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Nge-<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Mina"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Okukhethwa kukho kwethebhulethi"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Okukhethwa kukho kwefoni"</string>
@@ -238,11 +241,11 @@
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Qapha umbhalo owuthayiphayo"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kufaka phakathi idatha yomuntu siqu efana nezinombolo zekhadi lesikweletu namaphasiwedi."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"khubaza noma guqula ibha yomumo"</string>
- <string name="permdesc_statusBar" msgid="8434669549504290975">"Ivumela insiza ukuthi yenze umudwa ochaza ngesimo ukuthi ungasebenzi noma ukufaka noma ukukhipha izithonjana zohlelo."</string>
+ <string name="permdesc_statusBar" msgid="8434669549504290975">"Ivumela uhlelo lokusebenza ukuthi yenze umudwa ochaza ngesimo ukuthi ungasebenzi noma ukufaka noma ukukhipha izithonjana zohlelo."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"umudwa ochaza ngesimo"</string>
<string name="permdesc_statusBarService" msgid="716113660795976060">"Ivumela uhlelo lokusebenza ukuthi lube umudwa ochaza ngesimo."</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"khulisa/nciphisa ibha yomumo"</string>
- <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Ivumela insiza ukuthi ikhulise noma inciphise umudwa ochza ngesimo."</string>
+ <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Ivumela uhlelo lokusebenza ukuthi ikhulise noma inciphise umudwa ochza ngesimo."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"thumela amakholi aphumayo kabusha"</string>
<string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Ivumela uhlelo lokusebenza ukucubungula amakholi aphumayo futhi ishintshe inombolo ezoshayelwa. Le mvume ivumela uhlelo lokusebenza ukwengamela, liqondise kabusha, noma livikele amakholi aphumayo."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"thola imiyalezo ebhaliwe (i-SMS)"</string>
@@ -250,7 +253,7 @@
<string name="permlab_receiveMms" msgid="1821317344668257098">"thola imiyalezo ebhaliwe (i-MMS)"</string>
<string name="permdesc_receiveMms" msgid="533019437263212260">"Ivumela uhlelo lokusebenza ukuthola nokucubungula imilayezo ye-MMS. Loku kuchaza ukuthi uhlelo lokusebenza lungangamela noma lesuse imilayezo ethunyelwe kudivayisi yakho ngaphandle kokukubonisa yona."</string>
<string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"yamukela ukusakazwa okuphuthumayo"</string>
- <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Ivumela insiza ukuthi yamukele iphinde isebenze ukusakakwa kwemiyalezo yezokuphuthumayo. Imvume itholakla ezinsizeni zesistimu kuphela."</string>
+ <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Ivumela uhlelo lokusebenza ukuthi yamukele iphinde isebenze ukusakakwa kwemiyalezo yezokuphuthumayo. Imvume itholakla ezinsizeni zesistimu kuphela."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"funda imilayezo yokusakaza yeselula"</string>
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Ivumela uhlelo lokusebenza ukufunda imilayezo yokusakaza yeselula etholwe idivayisi yakho. Izaziso zokusakaza zeselula zilethwa kwezinye izindawo ukukuxwayisa ngezimo ezisheshayo. Izinhlelo zokusebenza ezingalungile zingaphazamisana nokusebenza noma umsebenzi wedivayisi yakho uma ukusakaza kweselula kwesimo esisheshayo kutholwa."</string>
<string name="permlab_sendSms" msgid="5600830612147671529">"thumela imiyalezo ye-SMS"</string>
@@ -261,11 +264,11 @@
<string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Ivumela uhlelo lokusebenza ukufunda imilayezo ye-SMS elondolozwe kuthebulethi noma ekhadini lakho le-SIM. Lokhu kuvumela uhlelo lokusebenza ukufunda yonke imilayezo ye-SMS, ngaphandle kokuqukethwe noma ukugcinwa kuyimfihlo."</string>
<string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Ivumela uhlelo lokusebenza ukufunda imilayezo ye-SMS elondolozwe efonini noma ekhadini lakho le-SIM. Lokhu kuvumela uhlelo lokusebenza ukufunda yonke imilayezo ye-SMS, ngaphandle kokuqukethwe noma ukugcinwa kuyimfihlo."</string>
<string name="permlab_writeSms" msgid="3216950472636214774">"hlela imiyalezo yakho yombhalo (i-SMS noma i-MMS)"</string>
- <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Ivumela insiza ukuthi ibhale imiylezo ye-SMS egcinwe ekhompyutheni yakho yepeni noma kwikhadi lakho le-SIM. Izinsiza ezinobungozi zingayisusa imiyalezo yakho."</string>
- <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Ivumela insiza ukuthi ibhale imiylezo ye-SMS egcinwe ocingweni lwakh noma kwikhadi lakho le-SIM. Izinsiza ezinobungozi zingayisusa imiyalezo yakho."</string>
+ <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Ivumela uhlelo lokusebenza ukuthi ibhale imiylezo ye-SMS egcinwe ekhompyutheni yakho yepeni noma kwikhadi lakho le-SIM. Izuhlelo lokusebenza ezinobungozi zingayisusa imiyalezo yakho."</string>
+ <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Ivumela uhlelo lokusebenza ukuthi ibhale imiylezo ye-SMS egcinwe ocingweni lwakh noma kwikhadi lakho le-SIM. Izuhlelo lokusebenza ezinobungozi zingayisusa imiyalezo yakho."</string>
<string name="permlab_receiveWapPush" msgid="5991398711936590410">"thola imiyalezo ebhaliwe (i-WAP)"</string>
<string name="permdesc_receiveWapPush" msgid="748232190220583385">"Ivumela uhlelo lokusebenza ukuthola nokucubungula imilayezo ye-WAP. Le mvume ifaka phakathi amandla okungamela noma okwesusa imilayezo ethunyelwe kuwe ngaphandle kokukubonisa."</string>
- <string name="permlab_getTasks" msgid="6466095396623933906">"thola izinsiza ezisebenzayo"</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"thola izinhlelo zokusebenza ezisebenzayo"</string>
<string name="permdesc_getTasks" msgid="7454215995847658102">"Ivumela uhlelo lokusebenza ukubuyisa ulwazi mayelana nemisebenzi yamanje neyakamuva. Lokhu kungavumela uhlelo lokusebenza ukuthola ulwazi mayelana nokuthi iziphi izinhlelo zokusebenza ezisetshenziswa kudivayisi."</string>
<string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"ihlanganyela phakathi kwabasebenzisi"</string>
<string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ivumela uhlelo lokusebenza ukwenza izenzo kubasebenzisi bonke kudivayisi. Izinhlelo zokusebenza ezingalungile zingasebenzisa lokhu ukwephula ukuvikela phakathi kwabasebenzisi."</string>
@@ -275,32 +278,32 @@
<string name="permdesc_manageUsers" msgid="8409306667645355638">"Ivumela izinhlelo zokusebenza ukuphatha abasebenzisi kudivayisi, kufaka phakathi umbuzo, ukudala nokususa."</string>
<string name="permlab_getDetailedTasks" msgid="6229468674753529501">"thola kabusha imininingwane yezinhlelo zokusebenza ezisebenzayo"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Ivumela uhlelo lokusebenza ukuthola kabusha ulwazi mayelana nezinto ezenzeka manje nezisanda kwenzeka. Izinhlelo zokusebenza ezingalungile zingathola imininingwane eyimfihlo mayelana nezinye izinhlelo zokusebenza."</string>
- <string name="permlab_reorderTasks" msgid="2018575526934422779">"misa kabusha izinsiza ezisebenzayo"</string>
+ <string name="permlab_reorderTasks" msgid="2018575526934422779">"misa kabusha izinhlelo zokusebenza ezisebenzayo"</string>
<string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ivumela uhlelo lokusebenza ukugudluza imisebenzi ngaphambili nangasemuva. Uhlelo lokusebenza lungenza lokhu ngaphandle kwakho."</string>
- <string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinsiza ezisebenzayo"</string>
- <string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi insiza isuse okumele kwenziwe ibulale nezinsiza zakho. Izinsiza eziwubungozi zingaphazamisa ukusebenza kwezinye izinsiza."</string>
+ <string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinhlelo zokusebenza ezisebenzayo"</string>
+ <string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi uhlelo lokusebenza isuse okumele kwenziwe ibulale nezuhlelo lokusebenza zakho. Izuhlelo lokusebenza eziwubungozi zingaphazamisa ukusebenza kwezinye izinhlelo zokusebenza."</string>
<string name="permlab_manageActivityStacks" msgid="7391191384027303065">"phatha izitaki zomsebenzi"</string>
<string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Ivumela uhlelo lokusebenza ukuthi lingeze, lisuse, noma lilungise izitaki zomsebenzi lapho ezinye izinhlelo zokusebenza ziqalisa khona. Izinhlelo zokusebenza ezinobungozi zingaphazamisa ukuziphatha kwezinye izinhlelo zokusebenza."</string>
<string name="permlab_startAnyActivity" msgid="2918768238045206456">"qala noma imuphi umsebenzi"</string>
<string name="permdesc_startAnyActivity" msgid="997823695343584001">"Ivumela uhlelo lokusebenza ukuqala umsebenzi, ngaphandle kokuvukeleka kwemvume noma isimo sokukhishiwe."</string>
<string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setha ukuhambelana kwesikrini"</string>
<string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ivumela uhlelo lokusebenza ukulawula imodi yokuhambelana kwesikrini kwezinye izinhlelo zokusebenza. Izinhlelo zokusebenza ezinonya zingase zephule ukuziphatha kwezinye izinhlelo zokusebenza."</string>
- <string name="permlab_setDebugApp" msgid="3022107198686584052">"vumela insiza ilungise inkinga"</string>
- <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ivumela insiza ukuthi ivule uhlelo lokulungisa lwenye insiza. Izinsiza ezinobungozi zingasebenzisa lokhu ukubulala ezinye izinsiza."</string>
+ <string name="permlab_setDebugApp" msgid="3022107198686584052">"vumela uhlelo lokusebenza ilungise inkinga"</string>
+ <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ivumela uhlelo lokusebenza ukuthi ivule uhlelo lokulungisa lwenye uhlelo lokusebenza. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukubulala ezinye izinhlelo zokusebenza."</string>
<string name="permlab_changeConfiguration" msgid="4162092185124234480">"guqula izilungiselo zohlelo zokubonisa"</string>
<string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Ivumela uhlelo lokusebenza ukushintsha ukumisa kwamanje, njengezici zakhona noma usayizi wefonti."</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"vumela imodi yemoto"</string>
- <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Ivumela insiza ukuthi yenze isimo semoto sisebenze."</string>
+ <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Ivumela uhlelo lokusebenza ukuthi yenze isimo semoto sisebenze."</string>
<string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"vala ezinye izinhlelo zokusebenza"</string>
<string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Ivumela uhelo lokusebenza ukuqeda izinqubo zangokwasemuva zezinhlelo zokusebenza. Lokhu kungababangela ezinye izinhlelo zokusebenza ukuyeka ukusebenza."</string>
- <string name="permlab_forceStopPackages" msgid="2329627428832067700">"phoqelela ezinye izinsiza ukuthi zime"</string>
- <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Ivumela insiza ukuthi iphoze ezinye izinsiza ukuthi zime."</string>
- <string name="permlab_forceBack" msgid="652935204072584616">"phoqa insiza ukuthi ivaleke"</string>
- <string name="permdesc_forceBack" msgid="3892295830419513623">"Ivumela insiza ukuthi iphoqe nanoma isiphi isehlo esiphambili ukuthi sivale bese sibuyela emuva. Akudingeki ezinsizeni ezejwayelekile."</string>
+ <string name="permlab_forceStopPackages" msgid="2329627428832067700">"phoqelela ezinye izinhlelo zokusebenza ukuthi zime"</string>
+ <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Ivumela uhlelo lokusebenza ukuthi iphoze ezinye izinhlelo zokusebenza ukuthi zime."</string>
+ <string name="permlab_forceBack" msgid="652935204072584616">"phoqa uhlelo lokusebenza ukuthi ivaleke"</string>
+ <string name="permdesc_forceBack" msgid="3892295830419513623">"Ivumela uhlelo lokusebenza ukuthi iphoqe nanoma isiphi isehlo esiphambili ukuthi sivale bese sibuyela emuva. Akudingeki ezinsizeni ezejwayelekile."</string>
<string name="permlab_dump" msgid="1681799862438954752">"thola isimo sangaphakathi sesistimu"</string>
- <string name="permdesc_dump" msgid="1778299088692290329">"Ivumela insiza ukuthi ithole kabusha ingaphakathi lesistimu. izinsiza ezinobungozi zingathola kabusha inqwaba yolwazi oluyimfihlo noluvikelekile ezingajwayele ukuthi ziludinge."</string>
+ <string name="permdesc_dump" msgid="1778299088692290329">"Ivumela uhlelo lokusebenza ukuthi ithole kabusha ingaphakathi lesistimu. izinhlelo zokusebenza ezinobungozi zingathola kabusha inqwaba yolwazi oluyimfihlo noluvikelekile ezingajwayele ukuthi ziludinge."</string>
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"letha okuqukethwe kwesikrini"</string>
- <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ivumela insiza ukuthi ithole okuqukethe kwi-Window. Izinsiza ezinobungozi zingathola kabush iwindi eliphelele bese ibheka konke okuqukethwe ngaphandle kwaaaphasiwedi."</string>
+ <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ivumela uhlelo lokusebenza ukuthi ithole okuqukethe kwi-Window. Izuhlelo lokusebenza ezinobungozi zingathola kabush iwindi eliphelele bese ibheka konke okuqukethwe ngaphandle kwaaaphasiwedi."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"nika amandla okwesikhashana ukufinyelela"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ivumela uhlelo lokusebenza ukunika amandla ukufinyelela kwesikhashana kuvidayisi. Izinhlelo zokusebenza ezingalungile zinganika amandla ukufinyelela ngaphandle kwemvume yomsebenzisi."</string>
<string name="permlab_retrieve_window_info" msgid="8532295199112519378">"buyisa ulwazi lewindi"</string>
@@ -315,18 +318,18 @@
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Igwema umsebenzisi ukuthi ashintshele kolunye uhlelo lokusebenza."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"thola ulwazi lohlelo lokusebenza lwamanje"</string>
<string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Ivumela umphathi ukuthi athole ulwazi oluyimfihlo mayelana nohlelo lokusebenza lwamanje ngaphambili kwesikrini."</string>
- <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"qapha futhi ulawule ukuqaliswa kwazo zonke izinsiza"</string>
+ <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"qapha futhi ulawule ukuqaliswa kwazo zonke izinhlelo zokusebenza"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Ivumela uhlelo lokusebebenza ukuthi luhlole futhi lulawule ukuthi isistimu iziqalisa kanjani imisebenzi. Izinhlelo zokusebenza ezinobungozi zingensa isistimu ibe sebungozini. Le mvume idingakalela intuthuku kuphela hhayi ukusetshenziswa okwejwayelekile."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"thumela iphakheji yomsakazo okhishiwe"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Ivumela insiza ukuthi isakaze isaziso sokuthi insiza ethize isusiwe. Izinsiza ezinobungozi zingasebenzisa lokhu ukubulala nanoma iyiphi enye insiza esebenzayo."</string>
+ <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi uhlelo lokusebenza ethize isusiwe. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukubulala nanoma iyiphi enye uhlelo lokusebenza esebenzayo."</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"thumela umsakazo otholwe nge-SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ivumela insiza ukuthi isakaze isaziso sokuthi umyalezo we-SMS utholakele. Izinsiza ezinobungozi zingasebenzisa lokhu ukufoja imiyalezo ye-SMS engenayo."</string>
+ <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-SMS utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja imiyalezo ye-SMS engenayo."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"thumela umsakazo otholwe nge-WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ivumela insiza ukuthi isakaze isaziso sokuthi umyalezo we-WAP PUSH utholakele. Izinsiza ezinobungozi zingasebenzisa lokhu ukufoja ukutholakala kwemiyalezo ye-S noma zisuse okuqukethwe kwanoma iliphi ikhasi lewebhu eliqukethe okunobungozi."</string>
+ <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-WAP PUSH utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja ukutholakala kwemiyalezo ye-S noma zisuse okuqukethwe kwanoma iliphi ikhasi lewebhu eliqukethe okunobungozi."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"khawula inani lezinqubo ezisebenzayo"</string>
- <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ivumela insiza ukuthi ilawule isibalo esikhulu sezinto eziqhubekayo eziyosebenza. Ayidingakeli izinsiza ezijwayelekile."</string>
+ <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ivumela uhlelo lokusebenza ukuthi ilawule isibalo esikhulu sezinto eziqhubekayo eziyosebenza. Ayidingakeli izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"phoqa izinhlelo zokusebenza ezingemuva ukuthi zivaleke"</string>
- <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Ivumela izinsiza ukuthi zilawule ukuthi izehlakalo ziyaphela yini emumva kokuba ziye ngemumva. Akudingakeli izinsiza ezijwayelekile."</string>
+ <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Ivumela izinhlelo zokusebenza ukuthi zilawule ukuthi izehlakalo ziyaphela yini emumva kokuba ziye ngemumva. Akudingakeli izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_batteryStats" msgid="2789610673514103364">"funda izibalo zebhethri"</string>
<string name="permdesc_batteryStats" msgid="5897346582882915114">"Ivumela uhlelo lokusebenza ukufunda idatha yokusebenza yebhethri leleveli ephansi yamanje. Ingavumela uhlelo lokusebenza ukuthola ulwazi lemininingwane mayelana nokuthi iziphi izinhlelo zokusebenza ozisebenzisayo."</string>
<string name="permlab_updateBatteryStats" msgid="3719689764536379557">"guqula izibalo zebhetri"</string>
@@ -336,24 +339,24 @@
<string name="permlab_updateAppOpsStats" msgid="8829097373851521505">"shintsha izinombolo zokusebenza zohlelo lokusebenza"</string>
<string name="permdesc_updateAppOpsStats" msgid="50784596594403483">"Ivumela uhlelo lokusebenza ukuthi lishintshe izinombolo zokusebenza kohlelo lokusebenza lokuqoqiwe. Akufanele kusetshenziswe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_backup" msgid="470013022865453920">"lawula ukusekela ngokulondoloza uhlelo bese ubuyisela esimweni"</string>
- <string name="permdesc_backup" msgid="6912230525140589891">"Ivumela insiza ukuthi ilawule isipele sesistimu kanye nohlelo lokubuyiselwa kabusha. Ayenzelwe ukusetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_backup" msgid="6912230525140589891">"Ivumela uhlelo lokusebenza ukuthi ilawule isipele sesistimu kanye nohlelo lokubuyiselwa kabusha. Ayenzelwe ukusetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_confirm_full_backup" msgid="5557071325804469102">"qinisekisa isipele sonke noma buyisela futhi ukusebenza"</string>
- <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Ivumela insiza ukuthi iqalise ukuqinisekiswa okuphelele kwesipele kwe-UI. Akumelwe kusetshenziswe noma iyiphi insiza."</string>
+ <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Ivumela uhlelo lokusebenza ukuthi iqalise ukuqinisekiswa okuphelele kwesipele kwe-UI. Akumelwe kusetshenziswe noma iyiphi uhlelo lokusebenza."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"bonisa amawindi angavunyelwe"</string>
- <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Ivumela insiza ukuthi yakhe amawindi enzelwe ukuthi asetshenziswe inkundla yokusetshenziswa kwangaphakathi kwesistimu. Ayisethsnziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Ivumela uhlelo lokusebenza ukuthi yakhe amawindi enzelwe ukuthi asetshenziswe inkundla yokusetshenziswa kwangaphakathi kwesistimu. Ayisethsnziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_systemAlertWindow" msgid="3543347980839518613">"dweba phezulu kwezinye izinhlelo zokusebenza"</string>
<string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Ivumela uhlelo lokusebenza ukudweba phezu kwezinye izinhlelo zokusebenza noma izingxene zokusetshenziswa ukubonwa. Zingaphazamisa ukusebenzisa kwakho kokusetshenziswa kubonwa kunoma uluphi uhlelo lokusebenza, noma ukushintsha ocabanga ukuthi uyakubona kwezinye izinhlelo zokusebenza."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"guqula isivinini sokugqwayiza jikelele"</string>
<string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Ivumela uhlelo lokusebenza ukushintsha isivinini sokugqwayiza jikelele (ukugqwayiza okusheshayo noma okulengayo) nganoma isiphi isikhathi."</string>
<string name="permlab_manageAppTokens" msgid="1286505717050121370">"lawula amathokheni ezinsiza"</string>
- <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Ivumela insiza ukuthi idale iphinde futhi ilawule amathokheni ayo, ngokweqa uku-oda kuka-Z okwejwayelekile. Akufanele kudingakele izinsiza ezijwayelekile."</string>
+ <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Ivumela uhlelo lokusebenza ukuthi idale iphinde futhi ilawule amathokheni ayo, ngokweqa uku-oda kuka-Z okwejwayelekile. Akufanele kudingakele izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_freezeScreen" msgid="4708181184441880175">"misa kancane isikrini"</string>
<string name="permdesc_freezeScreen" msgid="8558923789222670064">"Ivumela uhlelo lokusebenza ukumisa okwesikhashana isikrini ngokushintshwa kwesikrini esigcwele."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"chofoza okhiye nezinkinobho zokulawula"</string>
<string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Ivumela uhlelo lokusebenza ukuthi lizenzele izehlakalo zalo zokufaka (ukucindezela kokhiye, njll) kwezinye izinhlelo zokusebenza. Izinhlelo zokusebenza ezinobungozi zingasebenzisa lokhu ukuthi zilawule ithebhulethi."</string>
- <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Ivumela insiza ukuthi ithumele imicimbi yayo (ukucindezelwa kwezinkinobho, njll) kwezinye izinsiza. Izinsiza ezinobungozi zingasebenzisa lokhu ukuthi zilawule ucingo."</string>
+ <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Ivumela uhlelo lokusebenza ukuthi ithumele imicimbi yayo (ukucindezelwa kwezinkinobho, njll) kwezinye izinhlelo zokusebenza. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukuthi zilawule ucingo."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"qopha lokho okuthayiphayo nezinyathelo ozithathayo"</string>
- <string name="permdesc_readInputState" msgid="8387754901688728043">"Ivumela insiza ukuthi ibheke izinkinobho ozicindezelayo ngisho ngabe usebenzisana nezinye izinsiza (njengokubhala amaphasiwedi). Akufanele kudingakele izinsiza ezijwayelekile."</string>
+ <string name="permdesc_readInputState" msgid="8387754901688728043">"Ivumela uhlelo lokusebenza ukuthi ibheke izinkinobho ozicindezelayo ngisho ngabe usebenzisana nezinye izinhlelo zokusebenza (njengokubhala amaphasiwedi). Akufanele kudingakele izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"hlanganisa indlela yokufakwayo"</string>
<string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ivumela isimeli ukuhlanganisa uxhumano nomsebenzisi wezinga eliphezulu lendlela yokufaka. Ayisoze yadingeka kwizinhlelo ezivamile."</string>
<string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"hlanganisa kusevisi yokufinyeleleka"</string>
@@ -367,7 +370,7 @@
<string name="permlab_bindTextService" msgid="7358378401915287938">"bophezela kunsizakalo yombhalo"</string>
<string name="permdesc_bindTextService" msgid="8151968910973998670">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwesixhumi esibonakalayo sensizakalo yombhalo(isb. InsizakaloYokuhlolaUkubhala). Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"hlanganisa kwinsizakalo ye-VPN"</string>
- <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ivumela umnini ukuthi abophele kwissekelo esingaphezulu sesevisi ye-Vpm. Ayidingakeli izinsiza ezejwayelekile."</string>
+ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ivumela umnini ukuthi abophele kwissekelo esingaphezulu sesevisi ye-Vpm. Ayidingakeli izinhlelo zokusebenza ezejwayelekile."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"hlanganisa kwiphephadonga"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwephephadonga. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bophezela kube isevisi yesinqunjana"</string>
@@ -377,56 +380,56 @@
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"engeza noma susa umlawuli wedivayisi"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ivumela umnikazi ukuthi angeze noma asuse abalawuli bedivayisi esebenzayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"shintsha ukujikeleza kwesikrini"</string>
- <string name="permdesc_setOrientation" msgid="3046126619316671476">"Ivumela insiza ukuthi iguqule ukujikeleza kweskrini nganoma isiphi isikhathi. Akudingakeli izinsiza ezejwayelekile."</string>
+ <string name="permdesc_setOrientation" msgid="3046126619316671476">"Ivumela uhlelo lokusebenza ukuthi iguqule ukujikeleza kweskrini nganoma isiphi isikhathi. Akudingakeli izinhlelo zokusebenza ezejwayelekile."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"guqula isivinini sesikhombi"</string>
- <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ivumela insiza ukuthi iguqule ijubane legundane noma lendawo yokukhomba ngomunwe. Akufanele kudingakele izinsiza ezijwayelekile."</string>
+ <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ivumela uhlelo lokusebenza ukuthi iguqule ijubane legundane noma lendawo yokukhomba ngomunwe. Akufanele kudingakele izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"shintsha isendlalelo sekhibhodi"</string>
<string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Ivumela uhlelo lokusebenza ukushintsha isendlalelo sekhibhodi. Kufanele ingadingi izinhlelo zokusebenza ezivamile."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Thumela imifanekiso ye-Linu ezinsizeni"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ivumela insiza ukuthi icele ukuthi isiginali ethunyelwe idluliselwe kuzo zonke izinqubeko ezisalelayo."</string>
- <string name="permlab_persistentActivity" msgid="8841113627955563938">"yenza insiza ukuthi ihlale isebenza"</string>
+ <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ivumela uhlelo lokusebenza ukuthi icele ukuthi isiginali ethunyelwe idluliselwe kuzo zonke izinqubeko ezisalelayo."</string>
+ <string name="permlab_persistentActivity" msgid="8841113627955563938">"yenza uhlelo lokusebenza ukuthi ihlale isebenza"</string>
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Ivumela uhlelo kusebenza ukwenza izingxenye yazo ezicindezelayo kumemori. Lokhu kungakhawulela imemori ekhona kwezinye izinhlelo zokusebenza ukwenza ukuthi ithebhulethi ingasheshi."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Ivumela uhlelo kusebenza ukwenza izingxenye yazo ezicindezelayo kumemori. Lokhu kungakhawulela imemori ekhona kwezinye izinhlelo zokusebenza ukwenza ukuthi ifoni ingasheshi."</string>
- <string name="permlab_deletePackages" msgid="184385129537705938">"susa izinsiza"</string>
- <string name="permdesc_deletePackages" msgid="7411480275167205081">"Ivumela insiza ukuthi isuse amaphakheji e=Android. Izinsiza ezinobungozi zingasebenzisa lokhu ukusasa izinsiza ezibalulekile."</string>
+ <string name="permlab_deletePackages" msgid="184385129537705938">"susa izinhlelo zokusebenza"</string>
+ <string name="permdesc_deletePackages" msgid="7411480275167205081">"Ivumela uhlelo lokusebenza ukuthi isuse amaphakheji e=Android. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukusasa izinhlelo zokusebenza ezibalulekile."</string>
<string name="permlab_clearAppUserData" msgid="274109191845842756">"susa eminye imininingwane yezinsiza"</string>
- <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Ivumela insiza ukuth isule imininingwane yomsebenzisi."</string>
+ <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Ivumela uhlelo lokusebenza ukuth isule imininingwane yomsebenzisi."</string>
<string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"susa eminye imininingwane yezinsiza"</string>
- <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Ivumela insiza ukuthi isuse amafayela alondolozwe okwesikhashana."</string>
- <string name="permlab_getPackageSize" msgid="7472921768357981986">"linganisa isikhala sokugcina insiza"</string>
- <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Ivuela insiza ukuthi ithole kabusha ikhodi yayo, i-dat kanye nosayizi abagcinwe okwesikhashana."</string>
- <string name="permlab_installPackages" msgid="2199128482820306924">"faka ngqo izinsiza"</string>
- <string name="permdesc_installPackages" msgid="5628530972548071284">"Ivumela insiza ukuthi ifake amaphakheji e-Android amasha noma abuyekeziwe. Izinsiza ezinobungozi zngasebenzisa lokhu ukwengeza izinsiza ezintsha ezinemvume emndla."</string>
+ <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Ivumela uhlelo lokusebenza ukuthi isuse amafayela alondolozwe okwesikhashana."</string>
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"linganisa isikhala sokugcina uhlelo lokusebenza"</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Ivuela uhlelo lokusebenza ukuthi ithole kabusha ikhodi yayo, i-dat kanye nosayizi abagcinwe okwesikhashana."</string>
+ <string name="permlab_installPackages" msgid="2199128482820306924">"faka ngqo izinhlelo zokusebenza"</string>
+ <string name="permdesc_installPackages" msgid="5628530972548071284">"Ivumela uhlelo lokusebenza lufake amaphakheji e-Android amasha noma abuyekeziwe. Izinhlelo zokusebenza ezinobungozi zingasebenzisa lokhu ukwengeza izinhlelo ezinemvume enamandla."</string>
<string name="permlab_clearAppCache" msgid="7487279391723526815">"Susa yonke i-data egcinwe okwesikhashana yensiza"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"Ivumela uhlelo lokusebenza ukukhulula isitoreji se-tablet ngokususa amafayela enqolobaneni yezinye izinhlelo zokusebenza. Lokhu kungabangela ezinye izinhlelo zokusebenza ukuqala kancane njengoba zidinga ukubuyisa idatha yazo."</string>
<string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"Ivumela uhlelo lokusebenza ukukhulula isitoreji sefoni ngokususa amafayela enqolobaneni yezinye izinhlelo zokusebenza. Lokhu kungabangela ezinye izinhlelo zokusebenza ukuqala kancane njengoba zidinga ukubuyisa idatha yazo."</string>
<string name="permlab_movePackage" msgid="3289890271645921411">"hambis izinto zensiz"</string>
- <string name="permdesc_movePackage" msgid="319562217778244524">"Ivumela insiza ukuthi ihambise izinto eziqukethwe insiz izisusa emidiyeni yangaphakathi kuya kweyangaphandle njalonjalo."</string>
+ <string name="permdesc_movePackage" msgid="319562217778244524">"Ivumela uhlelo lokusebenza ukuthi ihambise izinto eziqukethwe insiz izisusa emidiyeni yangaphakathi kuya kweyangaphandle njalonjalo."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"funda idatha yefayela lokungena ebucayi"</string>
<string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Ivumela uhlelo lokusebenza ukufunda umafayela okungena ohlelo oluhlukene. Lokhu kuvumela ukuthola ukwaziswa okuvamile mayelana nokuthi wenzani ngethebhulethi, kodwa akumele kuqukethe ukwaziswa komuntu siqu noma okuyimfihlo."</string>
<string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Ivumela uhlelo lokusebenza ukufunda kumafayela okungena ahlukene esistimu. Lokhu kuvumela ukuthola ukwaziswa okuvamile mayelana nokuthi wenzani ngefoni, kuhlanganise ukwaziswa komuntu siqu noma kwangasese."</string>
<string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"sebenzisa noma isiphi isiqophi semidiya ukudlala"</string>
- <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela insiza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
+ <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela uhlelo lokusebenza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"phatha ukuqinisekisa okuthenjiwe"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ivumela uhlelo lokusebenza ukuthi lifake liphinde likhiphe izitifiketi ze-CA njengokuqinisekiswa okuthenjiwe."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"funda/bhalela emithombweni ephethwe idayegi"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ivumela uhlelo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonelo, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"vumela noma vimbela izingxenye zensiza"</string>
- <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Ivumela ukuthi insiza iguqule ukuthi okuqukethwe kwenye insiza kuyasebenza noma cha. Izinsiza ezinobungozi zingasebenzisa lokhu ukwenza ukuthi izinto ezisemqoka ekhompyutheni yepeni zingasebenzi. Kufanele kuqashelwe uma kukhishwa lemvume njengoba kungenzeka kwenze izinto zensiza zibe sesimweni esingazinzile, nesiguquguqukayo."</string>
- <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Ivumela ukuthi insiza iguqule ukuthi okuqukethwe kwenye insiza kuyasebenza noma cha. Izinsiza ezinobungozi zingasebenzisa lokhu ukwenza ukuthi izinto ezisemqoka ocingweni zingasebenzi. Kufanele kuqashelwe uma kukhishwa lemvume njengoba kungenzeka kwenze izinto zensiza zibe sesmweni esingazinzile, nesiguquguqukayo."</string>
+ <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Ivumela ukuthi uhlelo lokusebenza iguqule ukuthi okuqukethwe kwenye uhlelo lokusebenza kuyasebenza noma cha. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukwenza ukuthi izinto ezisemqoka ekhompyutheni yepeni zingasebenzi. Kufanele kuqashelwe uma kukhishwa lemvume njengoba kungenzeka kwenze izinto zensiza zibe sesimweni esingazinzile, nesiguquguqukayo."</string>
+ <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Ivumela ukuthi uhlelo lokusebenza iguqule ukuthi okuqukethwe kwenye uhlelo lokusebenza kuyasebenza noma cha. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukwenza ukuthi izinto ezisemqoka ocingweni zingasebenzi. Kufanele kuqashelwe uma kukhishwa lemvume njengoba kungenzeka kwenze izinto zensiza zibe sesmweni esingazinzile, nesiguquguqukayo."</string>
<string name="permlab_grantRevokePermissions" msgid="4627315351093508795">"nika noma buyisa izimvume"</string>
<string name="permdesc_grantRevokePermissions" msgid="4088642654085850662">"Ivumela izinhlelo zokusebenza ukunika noma ukubuyisa izimvume ezithile zayo noma ezinye izinhlelo zokusebenza. Izinhlelo zokusebenza ezingalungile zingasebenzisa lokhu ukufinyelela izici ongazinikanga zona."</string>
- <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"setha izinsiza ezincamelwayo"</string>
- <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Ivuela insiza ukuthi iguqule izinsiza ezincanyelwayo. Izinsiza ezinobungozi zingashintsha izinsiz buthule ezisebenzyo okwenza ukuthi izinsiza zakho ezikhona zingasebenzi ukuthola ze zithole imininingwane yakho eyimfihlo."</string>
+ <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"setha izinhlelo zokusebenza ezincamelwayo"</string>
+ <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Ivuela uhlelo lokusebenza ukuthi iguqule izinhlelo zokusebenza ezincanyelwayo. Izuhlelo lokusebenza ezinobungozi zingashintsha izinsiz buthule ezisebenzyo okwenza ukuthi izinhlelo zokusebenza zakho ezikhona zingasebenzi ukuthola ze zithole imininingwane yakho eyimfihlo."</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"guqula izilungiselelo zohlelo"</string>
- <string name="permdesc_writeSettings" msgid="7775723441558907181">"Ivumela insiza ukuthi iguqule i-data yezisetho zesistimu. Izinsiza ezinobungozi zingona ukusebenz kwesistimu yakho."</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"Ivumela uhlelo lokusebenza ukuthi iguqule i-data yezisetho zesistimu. Izuhlelo lokusebenza ezinobungozi zingona ukusebenz kwesistimu yakho."</string>
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"guqula izilungiselelo zohlelo oluphephile"</string>
- <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Ivumela insiza ukuthi iguqule imioniningwane yezisetho zokuphepha kwesistimu. Ayisetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Ivumela uhlelo lokusebenza ukuthi iguqule imioniningwane yezisetho zokuphepha kwesistimu. Ayisetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_writeGservices" msgid="2149426664226152185">"guqula ibalazwe lesevisi ye-Google"</string>
- <string name="permdesc_writeGservices" msgid="1287309437638380229">"Ivumela insiza ukuthi iguqule imephu yezinsizakalo ze-Google. Ayisetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_writeGservices" msgid="1287309437638380229">"Ivumela uhlelo lokusebenza ukuthi iguqule imephu yezuhlelo lokusebenzakalo ze-Google. Ayisetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"qalisa esiqalisweni sezinhlelo"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Ivumela uhlelo lokusebenza ukuthi luziqalise ngokushesha emuva kokuba isistimu isiqedile ukubhutha. Lokhu kwenza ukuthi ithathe isikhathi esithe ukuba side ukuqalise ithebhulethi nokuvumela izinhlelo zokusebenza ukuthi inciphise yonke ithebhulethi ngokuthi isebenze njalo."</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Ivumela insiza ukuthi iziqalise ngokushesha uma isistiu isiqedile ukubhutha. Lokhu kungenz ukuthi kuthathe isikhathi esithe ukuba side ukuqalisa ucingo nokuvuela insiz ukuthi inciphise ucingo lonke ngokuthi luhlale lusebenza."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Ivumela uhlelo lokusebenza ukuthi iziqalise ngokushesha uma isistiu isiqedile ukubhutha. Lokhu kungenz ukuthi kuthathe isikhathi esithe ukuba side ukuqalisa ucingo nokuvuela insiz ukuthi inciphise ucingo lonke ngokuthi luhlale lusebenza."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"thumela ukusakaza okunamathelayo"</string>
<string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Ivumela uhlelo lokusebenza ukuthumela ukusakaza okunamathelayo, okusalayo emva kokuba ukusakazwa sekuphelile. Ukusebenzisa kakhulu kuhle kwenze ithebhulethi ukuthi ingasheshi noma ingahlali kahle ngokuyibangela ukusebenzisa imemori eningi."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Ivumela uhlelo lokusebenza ukuthumela ukusakaza okunamathelayo, okusalayo emva kokuba ukusakazwa sekuphelile. Ukusebenzisa kakhulu kuhle kwenze ifoni ukuthi ingasheshi noma ingahlali kahle ngokuyibangela ukusebenzisa imemori eningi."</string>
@@ -467,15 +470,17 @@
<string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"indawo eseduze (kususelwe kunethiwekhi)"</string>
<string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Ivumela uhlelo lokusebenza ukuthola cishe indawo yakho. Le ndawo isuselwe kumasevisi endawo kusetshenziswa imithombo yendawo yenethiwekhi njengama-cell tower ne-Wi-Fi. Lawo masevisi endawo kufanele akhanyiswe futhi atholakale kudivayisi yakho ukuze asetshenziswe uhlelo lakho lokusebenza. Izinhlelo zokusebenza zingasebenzisa lokhu ukucacisa cishe lapho ukhona."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"finyelela i-SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ivumela insiza ukuthi isebenzise okuqukethwe i-SurfaceFlinger okusezingeni eliphansi."</string>
+ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ivumela uhlelo lokusebenza ukuthi isebenzise okuqukethwe i-SurfaceFlinger okusezingeni eliphansi."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"funda isikhumbuli sesikhashana sendikimba"</string>
- <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ivumela insiza ukuthi ifunde okuqukethwe ifreyimu yebhafa."</string>
+ <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ivumela uhlelo lokusebenza ukuthi ifunde okuqukethwe ifreyimu yebhafa."</string>
<string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"lungisa ukubukwa kwe-Wi-Fi"</string>
<string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ivumela uhlelo lokusebenza ukulungisa nokuxhuma ekubukisweni kwe-Wi-Fi."</string>
<string name="permlab_controlWifiDisplay" msgid="393641276723695496">"lawula ukubukwa kwe-Wi-Fi"</string>
<string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Uvumela uhlelo lokusebenza ukulawula izici zeleveli ephansi zokuboniswa kwe-Wi-Fi."</string>
<string name="permlab_captureAudioOutput" msgid="6857134498402346708">"shutha okukhipha umsindo"</string>
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Kuvumela uhlelo lokusebenza ukuba lushuthe futhi luqondise kabusha okukhipha umsindo."</string>
+ <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Ukutholwa kwe-Hotword"</string>
+ <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Ivumela uhlelo lokusebenza ukuthi lishuthele umsindo ukutholwa kwe-Hotword. Ukushutha kungenzeka ngemuva kodwa akuvimbeli okunye ukushutha komsindo (isb. i-Camcorder)."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"shutha okokukhipha ividiyo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Kuvumela uhlelo lokusebenza ukuba lushuthe futhi luqondise kabusha okukhipha ividiyo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"shutha okukhipha ividiyo ephephile"</string>
@@ -507,7 +512,7 @@
<string name="permlab_asec_create" msgid="6414757234789336327">"dala isitoreji sangaphakathi"</string>
<string name="permdesc_asec_create" msgid="4558869273585856876">"Ivumela uhlelo lokusebenza ukwenza ukugcina kwangaphakathi"</string>
<string name="permlab_asec_destroy" msgid="526928328301618022">"yonakalisa isitoreji sangaphakathi"</string>
- <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Ivumela insiza ukuthi ibulale ukulondolozwa kwangaphakathi."</string>
+ <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Ivumela uhlelo lokusebenza ukuthi ibulale ukulondolozwa kwangaphakathi."</string>
<string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"khweza / yehlisa isitoreji sangaphakathi"</string>
<string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Ivumela uhlelo ukukhuphula / ukwehlisa isitoreji sangaphakathi."</string>
<string name="permlab_asec_rename" msgid="7496633954080472417">"yetha kabusha isitoreji sangaphakathi"</string>
@@ -525,24 +530,27 @@
<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_callPrivileged" msgid="4198349211108497879">"ngokuqondile shayela noma iziphi izinombolo zocingo."</string>
- <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Ivumela insiza ukuth ishayele noma iyiphi inombolo okubandakanya nezinombolo eziphuthumayo ngaphandle kokugammbukela. zinsiza ezinobungozi zingafaka izingcingo ezingenasiidngo nezingekho emthethweni esevisini ephuthumayo."</string>
+ <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Ivumela uhlelo lokusebenza ukuth ishayele noma iyiphi inombolo okubandakanya nezinombolo eziphuthumayo ngaphandle kokugammbukela. zuhlelo lokusebenza ezinobungozi zingafaka izingcingo ezingenasiidngo nezingekho emthethweni esevisini ephuthumayo."</string>
<string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"ngokuqondile qalisa ukumisa ithebhulethi nge-CDMA"</string>
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"ngokuqondile qalisa ukumisa ifoni nge-CDMA"</string>
- <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Ivumela insiza ukuqalisa amalungiselelo e-CDMA. Izinsiza ezinobungozi ingaqalisa amalungiselelo e-CDMA ngokungenasidingo."</string>
+ <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Ivumela uhlelo lokusebenza ukuqalisa amalungiselelo e-CDMA. Izuhlelo lokusebenza ezinobungozi ingaqalisa amalungiselelo e-CDMA ngokungenasidingo."</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"lawula izaziso zokubuyekeza indawo"</string>
- <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Ivumela ukuthi insiza yenze izaziso zendawo zisebenze noma zingasebenzi emsakazweni. Ayenzelwe ukuthi isetshenziswe izinsiza ezijwayelekile."</string>
+ <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Ivumela ukuthi uhlelo lokusebenza yenze izaziso zendawo zisebenze noma zingasebenzi emsakazweni. Ayenzelwe ukuthi isetshenziswe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"finyelela kwizakhiwo zokuhlola"</string>
- <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Ivumela insiza ukuthi ifunde/ibhale ukufinyelela ezintweni ezilayishwe ngokubheka amasevisi. Akusetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Ivumela uhlelo lokusebenza ukuthi ifunde/ibhale ukufinyelela ezintweni ezilayishwe ngokubheka amasevisi. Akusetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"khetha izinqunjwana"</string>
- <string name="permdesc_bindGadget" msgid="8261326938599049290">"Ivumela insiza ukuthi itshele isistimu ukuthi amaphi amawijethi angasetshenziswa yiyiphi insiza. Insiza enalemvume inganikez ukufinyelela kwi-data yomuntu kwezinye izinsiza. Ayisetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_bindGadget" msgid="8261326938599049290">"Ivumela uhlelo lokusebenza ukuthi itshele isistimu ukuthi amaphi amawijethi angasetshenziswa yiyiphi uhlelo lokusebenza. Insiza enalemvume inganikez ukufinyelela kwi-data yomuntu kwezinye izinhlelo zokusebenza. Ayisetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"guqula isimo sefoni"</string>
- <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ivumela ukuthi insiza ilawule okuqukethwe ocingweni edivayisini. Insiza enalemvume ingaguquguqula amanethwekhi, ivule umsakazo wocingo iphinde iwucishe kanye nokunye okufana nalokho ngaphandle kokukwazisa."</string>
+ <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ivumela ukuthi uhlelo lokusebenza ilawule okuqukethwe ocingweni edivayisini. Insiza enalemvume ingaguquguqula amanethwekhi, ivule umsakazo wocingo iphinde iwucishe kanye nokunye okufana nalokho ngaphandle kokukwazisa."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"funda isimo sefoni kanye nesazisi"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ivumela uhlelo lokusebenza ukufinyelela izici zefoni zedivayisi. Le mvume ivumela uhlelo lokusebenza ukucacisa inombolo yefoni nobunikazi bedivayisi, ukuthi noma ikholi iyasebenza, futhi nenombolo yesilawuli kude zixhunywe ngekholi."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"gwema ithebhulethi ukuba ingalali"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"gwema ifoni ukuba ingalali"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ivumela uhlelo lokusebenza ukuthi linqande ithebulethi yakho ukuthi ilale."</string>
- <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ivumela insiza ukuthi inqande ucingo ukuthi lulale."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Ivumela uhlelo lokusebenza ukuthi inqande ucingo ukuthi lulale."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"hambisa okungabonwa ngeso"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Ivumela uhlelo lokusebenza ukuthi lusebenzise isihambisi esinombala ongabonwa ngeso wethebulethi."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Ivumela uhlelo lokusebenza ukuthi lusebenzise isihambisi esinombala ongabonwa ngeso wefoni."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"amandla efoni avuliwe noma avaliwe"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"amandla efoni avuliwe noma avaliwe"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Ivumela uhlelo lokusebenza ukuvala noma ukuvula ithebhulethi."</string>
@@ -555,15 +563,15 @@
<string name="permlab_setWallpaperHints" msgid="3278608165977736538">"shintsha usayizi wesithombe sakho sangemuva"</string>
<string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Ivumela uhlelo lokusebenza ukuhlela izihlawumbisela zosayizi wephephadonga lohlelo."</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"setha kabusha kube okumisiwe kwemboni"</string>
- <string name="permdesc_masterClear" msgid="3665380492633910226">"Ivuela insiza ukuthi isethe kabusha isistiu ngokuphelele iyibuyisele ezisethweni eyafika nazo, isusa konke ukumisw kwemininingwane, kanye nezinsiza ezifakiwe."</string>
+ <string name="permdesc_masterClear" msgid="3665380492633910226">"Ivuela uhlelo lokusebenza ukuthi isethe kabusha isistiu ngokuphelele iyibuyisele ezisethweni eyafika nazo, isusa konke ukumisw kwemininingwane, kanye nezuhlelo lokusebenza ezifakiwe."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"setha isikhathi"</string>
- <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Ivumela insiza ukuthi iguqule isikhathi esisekhompyutheni yepeni."</string>
- <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Ivumela insiza ukuth iguqule isikhathi esisocingweni."</string>
+ <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Ivumela uhlelo lokusebenza ukuthi iguqule isikhathi esisekhompyutheni yepeni."</string>
+ <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Ivumela uhlelo lokusebenza ukuth iguqule isikhathi esisocingweni."</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"setha umkhawulo wesikhathi"</string>
- <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Ivumela insiza ukuthi iguqule umkhawulo wesikhathi sekhompyutha yepeni."</string>
- <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Ivumela insiza ukuth iguqule isikhathi esisocingweni."</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Ivumela uhlelo lokusebenza ukuthi iguqule umkhawulo wesikhathi sekhompyutha yepeni."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Ivumela uhlelo lokusebenza ukuth iguqule isikhathi esisocingweni."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"yenza njenge Nsizakalo Yemeneja ye-Akhawunti"</string>
- <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Ivumela insiza ukuthi ishaye izingcingo Kokokuqinisekisa Ama-akhawunti."</string>
+ <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Ivumela uhlelo lokusebenza ukuthi ishaye izingcingo Kokokuqinisekisa Ama-akhawunti."</string>
<string name="permlab_getAccounts" msgid="1086795467760122114">"thola ama-akhawunti edivayisini"</string>
<string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Ivumela uhlelo lokusebenza ukuthola uhlu lwama-akhawunti aziwa ithebhulethi. Lokhu kufaka phakathi noma yimaphi ama-akhawunti adalwe izinhlelo zokusebenza ozifakile."</string>
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Ivumela uhlelo lokusebenza ukuthola uhlu lwama-akhawunti aziwa ifoni. Lokhu kufaka phakathi noma yimaphi ama-akhawunti adalwe izinhlelo zokusebenza ozifakile."</string>
@@ -572,17 +580,17 @@
<string name="permlab_manageAccounts" msgid="4983126304757177305">"engeza noma ukhiphe ama-akhawunti"</string>
<string name="permdesc_manageAccounts" msgid="8698295625488292506">"Ivumela uhlelo lokusebenza ukwenza imisebenzi enjengokufaka, nokukhipha ama-akhawunti nokususa iphasiwedi yawo"</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"sebenzisa ama-akhawunti edivayisini"</string>
- <string name="permdesc_useCredentials" msgid="7984227147403346422">"Ivumela insiza ukuthi icele amathokheni okuqinisekisa."</string>
+ <string name="permdesc_useCredentials" msgid="7984227147403346422">"Ivumela uhlelo lokusebenza ukuthi icele amathokheni okuqinisekisa."</string>
<string name="permlab_accessNetworkState" msgid="4951027964348974773">"buka ukuxhumeka kunethiwekhi"</string>
<string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Ivumela uhlelo lokusebenza ukubuka ulwazi mayelana noxhumo lenethiwekhi njengokuthi imaphi amanethiwekhi akhona futhi axhunyiwe."</string>
<string name="permlab_createNetworkSockets" msgid="8018758136404323658">"ukufinyelela kwenethiwekhi okugcwele"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Ivumela uhlelo lokusebenza ukudala amasokethi enethiwekhi nokusebenzisa iziphakamiso eziyisisekelo zenethiwekhi yezifiso. Iziphequluli nezinye izinhlelo zokusebenza zinikela ngezindlela zokuthumela idatha ku-intanethi, ngakho-le le mvume ayidingekile ukuthumela idatha ku-intanethi."</string>
<string name="permlab_writeApnSettings" msgid="505660159675751896">"shintsha/ngenelela izilungiselelo kanye nokuhamba kuhleloxhumano"</string>
- <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Ivumela insiza ukuthi iguqule izilungiselelo zenethiwekhi kanye nokunciphisa kanye nokuhlola konke ukuphithizela kwenethiwekhi, isibonelo ukushintsha i-proy kanye ne-port yanom iyiphi i-APN. Izinhlelo zokusebenza ezinobungozi zingabheka, zithumele kabusha noma ziguqule okuqukethwe enethiwekhini ngaphandle kokwazi kwakho."</string>
+ <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Ivumela uhlelo lokusebenza ukuthi iguqule izilungiselelo zenethiwekhi kanye nokunciphisa kanye nokuhlola konke ukuphithizela kwenethiwekhi, isibonelo ukushintsha i-proy kanye ne-port yanom iyiphi i-APN. Izinhlelo zokusebenza ezinobungozi zingabheka, zithumele kabusha noma ziguqule okuqukethwe enethiwekhini ngaphandle kokwazi kwakho."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"shintsha uxhumano lwenethiwekhi"</string>
- <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Ivumela insiza ukuthi iguqule isimo sokuxhuaniseka kwenethiwekhi."</string>
+ <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Ivumela uhlelo lokusebenza ukuthi iguqule isimo sokuxhuaniseka kwenethiwekhi."</string>
<string name="permlab_changeTetherState" msgid="5952584964373017960">"Shintsha uxhumano lokusebenzisa njengemodemu"</string>
- <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Ivumela insiza ukuthi iguqule isimo sokuxhuaniseka kwenethiwekhi ehunyiwe."</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Ivumela uhlelo lokusebenza ukuthi iguqule isimo sokuxhuaniseka kwenethiwekhi ehunyiwe."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"shintsha idatha yasemuva yelungiselelo lokusebenzisa"</string>
<string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Ivumela uhlelo lokusebenza ukuthi luguqule izilungiselelo zemininingwane yokusetshenziswa kwedatha."</string>
<string name="permlab_accessWifiState" msgid="5202012949247040011">"buka ukuxhumaneka kwi-Wi-Fi"</string>
@@ -604,7 +612,7 @@
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth kuthebhulethi, nokwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth efonini, ukwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"lawula Uxhumano Lwenkambu Eseduze"</string>
- <string name="permdesc_nfc" msgid="7120611819401789907">"Ivuela insiza ukuthi ixhumane ne-Near Field Communication (NFC) amathegi, amakhadi kanye nezinhlelo zokufunda."</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"Ivuela uhlelo lokusebenza ukuthi ixhumane ne-Near Field Communication (NFC) amathegi, amakhadi kanye nezinhlelo zokufunda."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"khubaza ukukhiya kwakho iskrini"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ivumela uhlelo lokusebenza ukukhubaza ukuvala ukhiye nanoma yikuphi ukuphepha kwephasiwedi okuhlobene. Isibonelo, ifoni ikhubaza ukuvala ukhiye lapho ithola ikholi yefoni engenayo, bese inike amandla kabusha ukuvala ukhiye lapho ikholi isiqedile."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"funda izilungiselelo zokuvumelanisa"</string>
@@ -614,37 +622,37 @@
<string name="permlab_readSyncStats" msgid="7396577451360202448">"funda izibalo zokuvumelanisa"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"Ivumela uhlelo lokusebenza ukufunda izibalo zokuvumelanisa ze-akhawunti, kufaka phakathi umlando wezehlakalo ezivumelanisiwe nokuthi ingakanani idatha evumelanisiwe."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"funda izifunzo ezikhokhelwayo"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Ivumela insiza ukuthi ithole imininingwane mayelana namafidi avumelnisiwe njengamanje."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Ivumela uhlelo lokusebenza ukuthi ithole imininingwane mayelana namafidi avumelnisiwe njengamanje."</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"bhala izifunzo ezikhokhelwayo"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Ivumela insiza ukuthi iguqule amafidi akho avumelanisiwe njengamanje. Izinsiza ezinobungozi zingaguqula amafidi akho avumelanisiwe."</string>
+ <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Ivumela uhlelo lokusebenza ukuthi iguqule amafidi akho avumelanisiwe njengamanje. Izuhlelo lokusebenza ezinobungozi zingaguqula amafidi akho avumelanisiwe."</string>
<string name="permlab_readDictionary" msgid="4107101525746035718">"funda imibandela oyengezile esichazimazwini"</string>
<string name="permdesc_readDictionary" msgid="659614600338904243">"Ivumela uhlelo lokusebenza ukufunda onke amabizo, amagama, namatemu umsebenzisi awalondolozile kusichazamazwi somsebenzisi."</string>
<string name="permlab_writeDictionary" msgid="2183110402314441106">"engeza amagama kusichazamazwi ezichazwe umsebenzisi"</string>
- <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Ivumela insiza ukuthi ibhale amagama amasha esichazinimazwi."</string>
+ <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Ivumela uhlelo lokusebenza ukuthi ibhale amagama amasha esichazinimazwi."</string>
<string name="permlab_sdcardRead" product="nosdcard" msgid="8235341515605559677">"ukufinyelela kokuhlola esilondolozini esivikelekile"</string>
<string name="permlab_sdcardRead" product="default" msgid="8235341515605559677">"ukufinyelela kokuhlola esilondolozini esivikelekile"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3642473292348132072">"Ivumela uhlelo lokusebenza ukuhlola imvume yesitoreji se-USB okuzotholakala kumadivayisi alandelayo."</string>
<string name="permdesc_sdcardRead" product="default" msgid="5914402684685848828">"Ivumela uhlelo lokusebenza ukuhlola imvume yekhadi le-SD okuzotholakala kumadivayisi alandelayo."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"guqula noma ususe okuqukethwe kwakho okugciniwe okufinyeleleka nge-USB"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"shintsha noma ususe okuqukethwe ekhadini lakho le-SD"</string>
- <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Ivumela insiza ukuthi ibhalele ekulondolozweni kwe-USB."</string>
- <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ivumela insiza ukuthi ibhalele ekhadini le-SD."</string>
+ <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Ivumela uhlelo lokusebenza ukuthi ibhalele ekulondolozweni kwe-USB."</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ivumela uhlelo lokusebenza ukuthi ibhalele ekhadini le-SD."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"guqula/susa okuqukethwe kwisitoreji semidiya yangaphakathi"</string>
- <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ivumela insiza ukuthi iguqule okuqukethwe kokulondoloza imidiya yangaphakathi."</string>
+ <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ivumela uhlelo lokusebenza ukuthi iguqule okuqukethwe kokulondoloza imidiya yangaphakathi."</string>
<string name="permlab_manageDocs" product="default" msgid="5778318598448849829">"phatha isitoreji sedokhumenti"</string>
<string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Ivumela uhlelo lokusebenza ukuthi luphathe isitoreji sedokhumenti."</string>
<string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"ukufinyelela isilondolozi sangaphandle sabo bonke abasebenzisi"</string>
<string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Vumela uhlelo lokusebenza ukufinyelela isilondolozi sangaphandle kubo bonke abasebenzisi."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"finyelela kunqolobane yesistimu yefayela"</string>
- <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ivumela insiza ukuthi ifunde futhi ibhale isistimu yokufayila amafayela esikhashana."</string>
+ <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ivumela uhlelo lokusebenza ukuthi ifunde futhi ibhale isistimu yokufayila amafayela esikhashana."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"yena/thola amakholi e-Inthanethi"</string>
- <string name="permdesc_use_sip" msgid="4717632000062674294">"Ivumela insiza ukuthi isebenzise isevisi ye-SIP ukwenza/ukuthola izingcingo ze-inthanethi."</string>
+ <string name="permdesc_use_sip" msgid="4717632000062674294">"Ivumela uhlelo lokusebenza ukuthi isebenzise isevisi ye-SIP ukwenza/ukuthola izingcingo ze-inthanethi."</string>
<string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"funda ukusetshenziswa komlando wohleloxhumano"</string>
- <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Ivumela insiza ukuthi ifunde umlando wokusetshenziswa kwenethiwekhi emanethiwekhini athize kanye nasezinsizeni."</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Ivumela uhlelo lokusebenza ukuthi ifunde umlando wokusetshenziswa kwenethiwekhi emanethiwekhini athize kanye nasezinsizeni."</string>
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"phatha inqubomgomo yenethiwekhi"</string>
- <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela insiza ukuthi yengamele iigomo iphinde ichaze imithetho ehambisana ngqo nensiza."</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela uhlelo lokusebenza ukuthi yengamele iigomo iphinde ichaze imithetho ehambisana ngqo nensiza."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"lungisa ukubala kokusebenza kohleloxhumano"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela insiza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela uhlelo lokusebenza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_markNetworkSocket" msgid="3658527214914959749">"shintsha izimpawu zesokhethi"</string>
<string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Ivumela uhlelo lokusebenza ukuthi lilungise izimpawu zesokhethi zomzila"</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"finyelela kuzaziso"</string>
@@ -655,8 +663,6 @@
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ivumela umnikazi ukuthi abuyisele uhlelo lokusebenza lokulungiselelwa. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Lalela okubonwayo kuzimo zenethiwekhi"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ivumela uhlelo lokusebenza ukuthi lulalele okubonwa kuzimo zenethiwekhi. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
- <string name="permlab_hotwordRecognition" msgid="3225080408746361313">"cela ukubonwa kwe-hotword"</string>
- <string name="permdesc_hotwordRecognition" msgid="3716741260195364252">"Ivumela uhlelo lokusebenza ukuthi lucele ukubonwa kwe-hotword. Akumele ifunelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
@@ -928,11 +934,11 @@
<string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Ivumela uhlelo lokusebenza ukushintsha umlando wamabhukhimakhi noma wesiphequluli alondolozwe kuthebhulethi yakho. Lokhu kungavumela uhlelo lokusebenza ukususa noma ukushintsha idatha yesiphequluli. Qaphela: le mvume kungenzeka ingaphoqelelwa iziphequluli ezivela eceleni noma ezinye izinhlelo zokusebenza ezinamandla okuphequlula iwebhu."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Ivumela uhlelo lokusebenza ukushintsha umlando wamabhukhimakhi noma wesiphequluli alondolozwe efonini yakho. Lokhu kungavumela uhlelo lokusebenza ukususa noma ukushintsha idatha yesiphequluli. Qaphela: le mvume kungenzeka ingaphoqelelwa iziphequluli ezivela eceleni noma ezinye izinhlelo zokusebenza ezinamandla okuphequlula iwebhu."</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"setha i-alamu"</string>
- <string name="permdesc_setAlarm" msgid="316392039157473848">"Ivumela insiza ukuthi isethe i-alamu ensizeni efkiwe ye-alamu. Ezinye izinsiza ze-alamu kungenzeka zingakusebenzisi lokho."</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"Ivumela uhlelo lokusebenza ukuthi isethe i-alamu ensizeni efkiwe ye-alamu. Ezinye izinhlelo zokusebenza ze-alamu kungenzeka zingakusebenzisi lokho."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"engeza imeyili yezwi"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Ivumela uhlelo lokusebenza ukwengeza imiyalezo kwibhokisi lakho lemeyili yezwi."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Gugula izimvume zendawo Yesiphequluli"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Ivumela insiza ukuthi iguqule izimvume eziphathelene nezindawo Zesiphequluli. Izinsiza eziyingozi zingasebenzisa lokhu ukuvumela ukuvumela imininingwane yendawo kunoma imaphi amawebusayithi."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Ivumela uhlelo lokusebenza ukuthi iguqule izimvume eziphathelene nezindawo Zesiphequluli. Izuhlelo lokusebenza eziyingozi zingasebenzisa lokhu ukuvumela ukuvumela imininingwane yendawo kunoma imaphi amawebusayithi."</string>
<string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"qinisekisa amaphakheji"</string>
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ivumela ukuthi isisetshenziswa siqinisekise ukuthi ngabe iphakheji iyafakeka."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bopha okokuqinisekisa iphakheji"</string>
@@ -1101,8 +1107,8 @@
<string name="alwaysUse" msgid="4583018368000610438">"Sebenzisa ngokuzenzakalelayo kulesenzo."</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Susa izilungiselelo zesistimu; Izinhlelo zokusebenza & Okulandiwe"</string>
<string name="chooseActivity" msgid="7486876147751803333">"Khetha okufanele kwenziwe"</string>
- <string name="chooseUsbActivity" msgid="6894748416073583509">"Kheth insiza yedivayisi ye-USB"</string>
- <string name="noApplications" msgid="2991814273936504689">"Azikho izinsiza ezingenza lokhu"</string>
+ <string name="chooseUsbActivity" msgid="6894748416073583509">"Kheth uhlelo lokusebenza yedivayisi ye-USB"</string>
+ <string name="noApplications" msgid="2991814273936504689">"Azikho izinhlelo zokusebenza ezingenza lokhu"</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
<string name="aerr_application" msgid="932628488013092776">"Ngeshwa, <xliff:g id="APPLICATION">%1$s</xliff:g> kumile."</string>
<string name="aerr_process" msgid="4507058997035697579">"Ngeshwa, uhlelo <xliff:g id="PROCESS">%1$s</xliff:g> luvele lwama."</string>
@@ -1120,21 +1126,21 @@
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> iqalisiwe."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Isilinganisi"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Bonisa njalo"</string>
- <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Yenza ukuthi kuphinde kusebenze lokhu ezisethweni Zesistimue > Izinsiza > Kulayishiwe."</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Yenza kuphinde kusebenze kuzilungiselelo Zesistimue > Izinhlelo zokusebenza > Okulayishiwe."</string>
<string name="smv_application" msgid="3307209192155442829">"Inqubo <xliff:g id="APPLICATION">%1$s</xliff:g> (yohlelo <xliff:g id="PROCESS">%2$s</xliff:g>) iphule inqubomgomo oziphoqelela yona Yemodi Ebukhali."</string>
<string name="smv_process" msgid="5120397012047462446">"Inqubo <xliff:g id="PROCESS">%1$s</xliff:g> yephule inqubomgomo yokuziphoqelela Yemodi Ebukhali."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"I-Android ifaka ezakamuva..."</string>
- <string name="android_upgrading_apk" msgid="7904042682111526169">"Ukubeka ezingeni eliphezulu <xliff:g id="NUMBER_0">%1$d</xliff:g> insiza <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
- <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Qalisa izinsiza."</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"Ukubeka ezingeni eliphezulu <xliff:g id="NUMBER_0">%1$d</xliff:g> uhlelo lokusebenza <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+ <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Qalisa izinhlelo zokusebenza."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Qedela ukuqala kabusha."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> iyasebenza"</string>
<string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Thinta ukuguqukela ensizeni"</string>
- <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Shintsha izinsiza?"</string>
+ <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Shintsha izinhlelo zokusebenza?"</string>
<string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Olunye uhlelo lokusebenza luvele luyasebenza lokho kumele kumiswe ngaphambi kokuba uqalise olusha."</string>
<string name="old_app_action" msgid="493129172238566282">"Buyisela ku:<xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="2082094275580358049">"Ungayiqali insiza entsha."</string>
+ <string name="old_app_description" msgid="2082094275580358049">"Ungayiqali uhlelo lokusebenza entsha."</string>
<string name="new_app_action" msgid="5472756926945440706">"Qala <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1932143598371537340">"Misa insiza endala ngaphandle kokulondoloza."</string>
+ <string name="new_app_description" msgid="1932143598371537340">"Misa uhlelo lokusebenza endala ngaphandle kokulondoloza."</string>
<string name="sendText" msgid="5209874571959469142">"Khetha okufanele kwenziwe okomqhafazo"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"Ivolumu yesishayeli"</string>
<string name="volume_music" msgid="5421651157138628171">"Ivolumu yemidiya"</string>
@@ -1229,7 +1235,7 @@
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Vala isitoreji se-USB"</string>
<string name="usb_storage_stop_error_message" msgid="1970374898263063836">"Kube nenkinga yokuvala okokulondoloza kwe-USB. Hlola ukuqiniseka ukuthi wehlise isikhungo se-USB, bese uzama futhi."</string>
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Vula isitoreji se-USB"</string>
- <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Uma uvula okokulondoloza kwe-USB, ezinye izinsiza ozisebenzisayo ziyoma futhi kungenzeka zingatholakali kuze kube ucisha ukulondoloza kwe-USB."</string>
+ <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Uma uvula okokulondoloza kwe-USB, ezinye izinhlelo zokusebenza ozisebenzisayo ziyoma futhi kungenzeka zingatholakali kuze kube ucisha ukulondoloza kwe-USB."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"Ukusebenza kwe-USB kwehlulekile"</string>
<string name="dlg_ok" msgid="7376953167039865701">"KULUNGILE"</string>
<string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ixhunyiwe njengedivayisi yemidiya"</string>
@@ -1278,9 +1284,9 @@
<string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"Ikhadi le-SD likhishiwe. Faka elisha."</string>
<string name="activity_list_empty" msgid="1675388330786841066">"Ayikho imisebenzi efanayo etholakele"</string>
<string name="permlab_pkgUsageStats" msgid="8787352074326748892">"buyekeza izibalo zokusebenzisa ingxenye"</string>
- <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Ivumela insiza ukuthi iguqule imininingwane yokusetshenziswa kokuqoqiwe. Akwenzelwe ukuthi kusetshenziswe izinsiza ezijwayelekile."</string>
+ <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Ivumela uhlelo lokusebenza ukuthi iguqule imininingwane yokusetshenziswa kokuqoqiwe. Akwenzelwe ukuthi kusetshenziswe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_copyProtectedData" msgid="4341036311211406692">"Kopisha okuqukethwe"</string>
- <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ivumela insiza ukuthi inqabe okutholakala kukhona ukukopisha okuqukethwe. Akusetshenziswa izinsiza ezijwayelekile."</string>
+ <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ivumela uhlelo lokusebenza ukuthi inqabe okutholakala kukhona ukukopisha okuqukethwe. Akusetshenziswa izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_route_media_output" msgid="1642024455750414694">"Yenza umzila wemidiya wokukhiphayo"</string>
<string name="permdesc_route_media_output" msgid="4932818749547244346">"Ivumela uhlelo lokusebenza ukwenza umzila wokukhiphayo wemidiya kuya kumadivayisi angaphandle."</string>
<string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Finyelela kusitoreji esiqashwa ngesikhiya esiphephile"</string>
@@ -1395,7 +1401,7 @@
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Ukushintsha kwendlela esetshenziswayo"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Beka kwenye indawo"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Faka"</string>
- <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Khetha insiza"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Khetha uhlelo lokusebenza"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Yabelana no"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Yabelana no <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Ihaambis isibambo. Thinta & ubambe."</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d2ada7a..80810d5 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1048,6 +1048,11 @@
tag; often this is one of the {@link android.Manifest.permission standard
system permissions}. -->
<attr name="name" />
+ <!-- Optional: specify the maximum version of the Android OS for which the
+ application wishes to request the permission. When running on a version
+ of Android higher than the number given here, the permission will not
+ be requested. -->
+ <attr name="maxSdkVersion" format="integer" />
<!-- Specify whether this permission is required for the application.
The default is true, meaning the application requires the
permission, and it must always be granted when it is installed.
@@ -1129,7 +1134,7 @@
on. You can use this to ensure your application is filtered out
of later versions of the platform when you know you have
incompatibility with them. -->
- <attr name="maxSdkVersion" format="integer" />
+ <attr name="maxSdkVersion" />
</declare-styleable>
<!-- The <code>library</code> tag declares that this apk is providing itself
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d4b834a..2c1a3c1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1241,4 +1241,8 @@
To do this, add 21407 item to values-mcc214-mnc04/config.xml -->
<string-array translatable="false" name="config_operatorConsideredNonRoaming">
</string-array>
+
+ <!-- Threshold (in ms) under which a screen off / screen on will be considered a reset of the
+ transient navigation confirmation prompt.-->
+ <integer name="config_transient_navigation_confirmation_panic">5000</integer>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a7dd313..99b703b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -273,6 +273,18 @@
<!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
<string name="low_memory" product="default">Phone storage is full. Delete some files to free space.</string>
+ <!-- SSL CA cert notification --> <skip />
+ <!-- Shows up when there is a user SSL CA Cert installed on the
+ device. Indicates to the user that SSL traffic can be intercepted. [CHAR LIMIT=NONE] -->
+ <string name="ssl_ca_cert_warning">Network may be monitored</string>
+ <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
+ i.e. "Network may be monitored". This says that an unknown party is doing the monitoring.
+ [CHAR LIMIT=100]-->
+ <string name="ssl_ca_cert_noti_by_unknown">By an unknown third party</string>
+ <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
+ i.e. "Network may be monitored". This indicates who is doing the monitoring.
+ [CHAR LIMIT=100]-->
+ <string name="ssl_ca_cert_noti_managed">By <xliff:g id="managing_domain">%s</xliff:g></string>
<!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
<string name="me">Me</string>
@@ -1886,6 +1898,11 @@
<string name="permdesc_use_sip">Allows the app to use the SIP service to make/receive Internet calls.</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_bind_call_service">interact with in-call screen</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_bind_call_service">Allows the app to control when and how the user sees the in-call screen.</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_readNetworkUsageHistory">read historical network usage</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_readNetworkUsageHistory">Allows the app to read historical network usage for specific networks and apps.</string>
@@ -4424,9 +4441,7 @@
<!-- PIN entry dialog tells the user to not enter a PIN for a while. [CHAR LIMIT=none] -->
<string name="restr_pin_try_later">Try again later</string>
- <!-- Toast bar message when hiding the transient navigation bar [CHAR LIMIT=35] -->
- <string name="transient_navigation_confirmation">Swipe edge of screen to reveal bar</string>
+ <!-- Toast bar message when hiding the transient navigation bar [CHAR LIMIT=45] -->
+ <string name="transient_navigation_confirmation">Swipe down from the top to exit full screen</string>
- <!-- Longer version of toast bar message when hiding the transient navigation bar (if room) -->
- <string name="transient_navigation_confirmation_long">Swipe from edge of screen to reveal system bar</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b557249..e82c0e1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -301,6 +301,7 @@
<java-symbol type="integer" name="config_ntpThreshold" />
<java-symbol type="integer" name="config_ntpTimeout" />
<java-symbol type="integer" name="config_toastDefaultGravity" />
+ <java-symbol type="integer" name="config_transient_navigation_confirmation_panic" />
<java-symbol type="integer" name="config_wifi_framework_scan_interval" />
<java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
<java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
@@ -927,7 +928,9 @@
<java-symbol type="string" name="write_fail_reason_cancelled" />
<java-symbol type="string" name="write_fail_reason_cannot_write" />
<java-symbol type="string" name="transient_navigation_confirmation" />
- <java-symbol type="string" name="transient_navigation_confirmation_long" />
+ <java-symbol type="string" name="ssl_ca_cert_noti_by_unknown" />
+ <java-symbol type="string" name="ssl_ca_cert_noti_managed" />
+ <java-symbol type="string" name="ssl_ca_cert_warning" />
<java-symbol type="plurals" name="abbrev_in_num_days" />
<java-symbol type="plurals" name="abbrev_in_num_hours" />
@@ -1050,6 +1053,7 @@
<java-symbol type="drawable" name="stat_notify_rssi_in_range" />
<java-symbol type="drawable" name="stat_sys_gps_on" />
<java-symbol type="drawable" name="stat_sys_tether_wifi" />
+ <java-symbol type="drawable" name="stat_sys_certificate_info" />
<java-symbol type="drawable" name="status_bar_background" />
<java-symbol type="drawable" name="sym_keyboard_shift" />
<java-symbol type="drawable" name="sym_keyboard_shift_locked" />
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index b76c8be..1649268 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -23,13 +23,6 @@
which is needed when building test cases. -->
<application>
<uses-library android:name="android.test.runner" />
- <activity android:name="ConnectivityManagerTestActivity"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
</application>
<!--
@@ -87,4 +80,6 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
+
</manifest>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 0461c0b..b942eb6 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -32,13 +32,11 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
-import android.util.Log;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
similarity index 88%
rename from core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
rename to core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index a0cb1bb..30eda75 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -16,7 +16,7 @@
package com.android.connectivitymanagertest;
-import android.app.Activity;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.BroadcastReceiver;
import android.content.Intent;
@@ -26,21 +26,14 @@
import android.net.NetworkInfo.State;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.os.Bundle;
import android.os.Handler;
-import android.os.IPowerManager;
import android.os.Message;
import android.os.PowerManager;
-import android.os.ServiceManager;
import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
+import android.test.InstrumentationTestCase;
import android.util.Log;
import android.view.KeyEvent;
-import android.widget.LinearLayout;
import com.android.internal.util.AsyncChannel;
@@ -52,13 +45,17 @@
/**
- * An activity registered with connectivity manager broadcast
- * provides network connectivity information and
- * can be used to set device states: Cellular, Wifi, Airplane mode.
+ * Base InstrumentationTestCase for Connectivity Manager (CM) test suite
+ *
+ * It registers connectivity manager broadcast and WiFi broadcast to provide
+ * network connectivity information, also provides a set of utility functions
+ * to modify and verify connectivity states.
+ *
+ * A CM test case should extend this base class.
*/
-public class ConnectivityManagerTestActivity extends Activity {
+public class ConnectivityManagerTestBase extends InstrumentationTestCase {
- public static final String LOG_TAG = "ConnectivityManagerTestActivity";
+ public static final String LOG_TAG = "ConnectivityManagerTestBase";
public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
public static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds
public static final int SHORT_TIMEOUT = 5 * 1000; // 5 seconds
@@ -94,14 +91,9 @@
private Context mContext;
public boolean scanResultAvailable = false;
- /*
- * Control Wifi States
- */
+ /* Control Wifi States */
public WifiManager mWifiManager;
-
- /*
- * Verify connectivity state
- */
+ /* Verify connectivity state */
public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
@@ -208,26 +200,28 @@
}
}
- public ConnectivityManagerTestActivity() {
+ @Override
+ public void setUp() throws Exception {
mState = State.UNKNOWN;
scanResultAvailable = false;
- }
+ mContext = getInstrumentation().getContext();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- log("onCreate, inst=" + Integer.toHexString(hashCode()));
+ // Get an instance of ConnectivityManager
+ mCM = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ // Get an instance of WifiManager
+ mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
- // Create a simple layout
- LinearLayout contentView = new LinearLayout(this);
- contentView.setOrientation(LinearLayout.VERTICAL);
- setContentView(contentView);
- setTitle("ConnectivityManagerTestActivity");
+ if (mWifiManager.isWifiApEnabled()) {
+ // if soft AP is enabled, disable it
+ mWifiManager.setWifiApEnabled(null, false);
+ log("Disable soft ap");
+ }
+ initializeNetworkStates();
// register a connectivity receiver for CONNECTIVITY_ACTION;
mConnectivityReceiver = new ConnectivityReceiver();
- registerReceiver(mConnectivityReceiver,
+ mContext.registerReceiver(mConnectivityReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
mWifiReceiver = new WifiReceiver();
@@ -238,28 +232,15 @@
mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
- registerReceiver(mWifiReceiver, mIntentFilter);
+ mContext.registerReceiver(mWifiReceiver, mIntentFilter);
- // Get an instance of ConnectivityManager
- mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
- // Get an instance of WifiManager
- mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE);
- mContext = this;
-
- if (mWifiManager.isWifiApEnabled()) {
- // if soft AP is enabled, disable it
- mWifiManager.setWifiApEnabled(null, false);
- log("Disable soft ap");
- }
-
- initializeNetworkStates();
log("Clear Wifi before we start the test.");
removeConfiguredNetworksAndDisableWifi();
mWifiRegexs = mCM.getTetherableWifiRegexs();
}
public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
- InputStream in = getAssets().open(ACCESS_POINT_FILE);
+ InputStream in = mContext.getAssets().open(ACCESS_POINT_FILE);
mParseHelper = new AccessPointParserHelper(in);
return mParseHelper.getNetworkConfigurations();
}
@@ -277,6 +258,12 @@
public void recordNetworkState(int networkType, State networkState) {
log("record network state for network " + networkType +
", state is " + networkState);
+ if (connectivityState == null) {
+ log("ConnectivityState is null");
+ }
+ if (connectivityState[networkType] == null) {
+ log("connectivityState[networkType] is null");
+ }
connectivityState[networkType].recordState(networkState);
}
@@ -503,7 +490,7 @@
public void turnScreenOff() {
log("Turn screen off");
PowerManager pm =
- (PowerManager) getSystemService(Context.POWER_SERVICE);
+ (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis());
}
@@ -511,8 +498,13 @@
public void turnScreenOn() {
log("Turn screen on");
PowerManager pm =
- (PowerManager) getSystemService(Context.POWER_SERVICE);
+ (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.wakeUp(SystemClock.uptimeMillis());
+ // disable lock screen
+ KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ if (km.inKeyguardRestrictedInputMode()) {
+ sendKeys(KeyEvent.KEYCODE_MENU);
+ }
}
/**
@@ -607,7 +599,12 @@
mWifiManager.setWifiEnabled(true);
sleep(SHORT_TIMEOUT);
}
+
List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
+ if (wifiConfigList == null) {
+ log("no configuration list is null");
+ return true;
+ }
log("size of wifiConfigList: " + wifiConfigList.size());
for (WifiConfiguration wifiConfig: wifiConfigList) {
log("remove wifi configuration: " + wifiConfig.networkId);
@@ -656,57 +653,15 @@
}
@Override
- protected void onDestroy() {
- super.onDestroy();
-
+ public void tearDown() throws Exception{
//Unregister receiver
if (mConnectivityReceiver != null) {
- unregisterReceiver(mConnectivityReceiver);
+ mContext.unregisterReceiver(mConnectivityReceiver);
}
if (mWifiReceiver != null) {
- unregisterReceiver(mWifiReceiver);
+ mContext.unregisterReceiver(mWifiReceiver);
}
- log("onDestroy, inst=" + Integer.toHexString(hashCode()));
- }
-
- @Override
- public void onStart() {
- super.onStart();
- mContext = this;
- Bundle bundle = this.getIntent().getExtras();
- if (bundle != null){
- mPowerSsid = bundle.getString("power_ssid");
- }
- }
- //A thread to set the device into airplane mode then turn on wifi.
- Thread setDeviceWifiAndAirplaneThread = new Thread(new Runnable() {
- public void run() {
- mCM.setAirplaneMode(true);
- connectToWifi(mPowerSsid);
- }
- });
-
- //A thread to set the device into wifi
- Thread setDeviceInWifiOnlyThread = new Thread(new Runnable() {
- public void run() {
- connectToWifi(mPowerSsid);
- }
- });
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- //This is a tricky way for the scripted monkey to
- //set the device in wifi and wifi in airplane mode.
- case KeyEvent.KEYCODE_1:
- setDeviceWifiAndAirplaneThread.start();
- break;
-
- case KeyEvent.KEYCODE_2:
- setDeviceInWifiOnlyThread.start();
- break;
- }
- return super.onKeyDown(keyCode, event);
+ super.tearDown();
}
private void log(String message) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
index 3a78f26..0e57a00 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
@@ -16,10 +16,8 @@
package com.android.connectivitymanagertest;
-import android.os.Bundle;
import android.test.InstrumentationTestRunner;
import android.test.InstrumentationTestSuite;
-import android.util.Log;
import com.android.connectivitymanagertest.unit.WifiClientTest;
import com.android.connectivitymanagertest.unit.WifiSoftAPTest;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index 729e1d2..05462b4 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -24,31 +24,24 @@
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.provider.Settings;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
import com.android.connectivitymanagertest.NetworkState;
public class ConnectivityManagerMobileTest extends
- ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
- private static final String LOG_TAG = "ConnectivityManagerMobileTest";
+ ConnectivityManagerTestBase {
+ private static final String TAG = "ConnectivityManagerMobileTest";
private String mTestAccessPoint;
- private ConnectivityManagerTestActivity cmActivity;
private WakeLock wl;
private boolean mWifiOnlyFlag;
- public ConnectivityManagerMobileTest() {
- super(ConnectivityManagerTestActivity.class);
- }
-
@Override
public void setUp() throws Exception {
super.setUp();
- cmActivity = getActivity();
ConnectivityManagerTestRunner mRunner =
(ConnectivityManagerTestRunner)getInstrumentation();
mTestAccessPoint = mRunner.mTestSsid;
@@ -62,12 +55,12 @@
if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON) == 1) {
log("airplane is not disabled, disable it.");
- cmActivity.mCM.setAirplaneMode(false);
+ mCM.setAirplaneMode(false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
+ if (!waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT)) {
// Note: When the test fails in setUp(), tearDown is not called. In that case,
// the activity is destroyed which blocks the next test at "getActivity()".
// tearDown() is called here to avoid that situation.
@@ -79,29 +72,22 @@
@Override
public void tearDown() throws Exception {
- cmActivity.finish();
- log("tear down ConnectivityManagerTestActivity");
wl.release();
- cmActivity.removeConfiguredNetworksAndDisableWifi();
- // if airplane mode is set, disable it.
- if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON) == 1) {
- log("disable airplane mode if it is enabled");
- cmActivity.mCM.setAirplaneMode(false);
- }
+ removeConfiguredNetworksAndDisableWifi();
+ mCM.setAirplaneMode(false);
super.tearDown();
}
// help function to verify 3G connection
public void verifyCellularConnection() {
- NetworkInfo extraNetInfo = cmActivity.mCM.getActiveNetworkInfo();
+ NetworkInfo extraNetInfo = mCM.getActiveNetworkInfo();
assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE,
extraNetInfo.getType());
assertTrue("not connected to cellular network", extraNetInfo.isConnected());
}
private void log(String message) {
- Log.v(LOG_TAG, message);
+ Log.v(TAG, message);
}
private void sleep(long sleeptime) {
@@ -115,46 +101,46 @@
@LargeTest
public void test3GToWifiNotification() {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
// Enable Wi-Fi to avoid initial UNKNOWN state
- cmActivity.enableWifi();
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ enableWifi();
+ sleep(2 * SHORT_TIMEOUT);
// Wi-Fi is disabled
- cmActivity.disableWifi();
+ disableWifi();
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
// Wait for 10 seconds for broadcasts to be sent out
sleep(10 * 1000);
// As Wifi stays in DISCONNETED, Mobile statys in CONNECTED,
// the connectivity manager will not broadcast any network connectivity event for Wifi
- NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(), NetworkState.DO_NOTHING, State.CONNECTED);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.DO_NOTHING, State.DISCONNECTED);
// Eanble Wifi without associating with any AP
- cmActivity.enableWifi();
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ enableWifi();
+ sleep(2 * SHORT_TIMEOUT);
// validate state and broadcast
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("the state for WIFI is changed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue("state validation fail", false);
}
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("the state for MOBILE is changed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue("state validation fail", false);
}
// Verify that the device is still connected to MOBILE
@@ -168,40 +154,39 @@
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
//Prepare for connectivity verification
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(), NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
// Enable Wifi and connect to a test access point
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
+ connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
log("wifi state is enabled");
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
}
// validate states
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
}
@@ -213,61 +198,59 @@
assertNotNull("SSID is null", mTestAccessPoint);
// Connect to mTestAccessPoint
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifi(mTestAccessPoint));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ sleep(SHORT_TIMEOUT);
// Disable Wifi
log("Disable Wifi");
- if (!cmActivity.disableWifi()) {
+ if (!disableWifi()) {
log("disable Wifi failed");
return;
}
// Wait for the Wifi state to be DISABLED
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
}
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
//Prepare for connectivity state verification
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(), NetworkState.DO_NOTHING,
State.DISCONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
// wait for 2 minutes before restart wifi
- sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL);
+ sleep(WIFI_STOP_START_INTERVAL);
// Enable Wifi again
log("Enable Wifi again");
- cmActivity.enableWifi();
+ enableWifi();
// Wait for Wifi to be connected and mobile to be disconnected
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
}
// validate wifi states
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
}
@@ -279,48 +262,48 @@
// connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
+ connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
// Wait for a few seconds to avoid the state that both Mobile and Wifi is connected
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ sleep(SHORT_TIMEOUT);
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.TO_CONNECTION,
State.CONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
// clear Wifi
- cmActivity.removeConfiguredNetworksAndDisableWifi();
+ removeConfiguredNetworksAndDisableWifi();
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
}
// validate states
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
}
@@ -330,62 +313,62 @@
@LargeTest
public void testDataConnectionWith3GToAmTo3G() {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
//Prepare for state verification
- NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.TO_DISCONNECTION,
State.DISCONNECTED);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
// Enable airplane mode
log("Enable airplane mode");
- cmActivity.mCM.setAirplaneMode(true);
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ mCM.setAirplaneMode(true);
+ sleep(SHORT_TIMEOUT);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
// wait until mobile is turn off
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
// reset state recorder
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.TO_CONNECTION,
State.CONNECTED);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.DO_NOTHING, State.DISCONNECTED);
// disable airplane mode
- cmActivity.mCM.setAirplaneMode(false);
+ mCM.setAirplaneMode(false);
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
// Validate the state transition
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
}
@@ -394,107 +377,107 @@
@LargeTest
public void testDataConnectionOverAMWithWifi() {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
assertNotNull("SSID is null", mTestAccessPoint);
// Eanble airplane mode
log("Enable airplane mode");
- cmActivity.mCM.setAirplaneMode(true);
+ mCM.setAirplaneMode(true);
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.DO_NOTHING,
State.DISCONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
// Connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifi(mTestAccessPoint));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
// validate state and broadcast
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("state validate for Wifi failed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue("State validation failed", false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("state validation for Mobile failed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue("state validation failed", false);
}
}
- cmActivity.mCM.setAirplaneMode(false);
+ mCM.setAirplaneMode(false);
}
// Test case 7: test connectivity while transit from Wifi->AM->Wifi
@LargeTest
public void testDataConnectionWithWifiToAMToWifi () {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
// Connect to mTestAccessPoint
assertNotNull("SSID is null", mTestAccessPoint);
// Connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
+ connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (Exception e) {
log("exception: " + e.toString());
}
// Enable airplane mode without clearing Wifi
- cmActivity.mCM.setAirplaneMode(true);
+ mCM.setAirplaneMode(true);
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (Exception e) {
log("exception: " + e.toString());
}
// Prepare for state validation
- NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
networkInfo.getState(), NetworkState.TO_CONNECTION, State.CONNECTED);
// Disable airplane mode
- cmActivity.mCM.setAirplaneMode(false);
+ mCM.setAirplaneMode(false);
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
}
// validate the state transition
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
}
@@ -505,35 +488,33 @@
assertNotNull("SSID is null", mTestAccessPoint);
//Connect to mTestAccessPoint
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifi(mTestAccessPoint));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
assertNotNull("Not associated with any AP",
- cmActivity.mWifiManager.getConnectionInfo().getBSSID());
+ mWifiManager.getConnectionInfo().getBSSID());
try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (Exception e) {
log("exception: " + e.toString());
}
// Disconnect from the current AP
log("disconnect from the AP");
- if (!cmActivity.disconnectAP()) {
+ if (!disconnectAP()) {
log("failed to disconnect from " + mTestAccessPoint);
}
// Verify the connectivity state for Wifi is DISCONNECTED
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
- if (!cmActivity.disableWifi()) {
+ if (!disableWifi()) {
log("disable Wifi failed");
return;
}
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
index f12e62e..183f2a9 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
@@ -16,7 +16,7 @@
package com.android.connectivitymanagertest.functional;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.WifiAssociationTestRunner;
import android.content.Context;
@@ -32,7 +32,6 @@
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
import android.test.suitebuilder.annotation.LargeTest;
-import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
/**
@@ -43,30 +42,22 @@
* -w com.android.connectivitymanagertest/.WifiAssociationTestRunner"
*/
public class WifiAssociationTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private static final String TAG = "WifiAssociationTest";
- private ConnectivityManagerTestActivity mAct;
private String mSsid = null;
private String mPassword = null;
private String mSecurityType = null;
private String mFrequencyBand = null;
private int mBand;
- private WifiManager mWifiManager = null;
enum SECURITY_TYPE {
OPEN, WEP64, WEP128, WPA_TKIP, WPA2_AES
- };
-
- public WifiAssociationTest() {
- super(ConnectivityManagerTestActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
WifiAssociationTestRunner mRunner = (WifiAssociationTestRunner)getInstrumentation();
- mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
- mAct = getActivity();
Bundle arguments = mRunner.getArguments();
mSecurityType = arguments.getString("security-type");
mSsid = arguments.getString("ssid");
@@ -77,17 +68,15 @@
assertNotNull("Ssid is empty", mSsid);
validateFrequencyBand();
// enable Wifi and verify wpa_supplicant is started
- assertTrue("enable Wifi failed", mAct.enableWifi());
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "interrupted while waiting for WPA_SUPPLICANT to start");
- WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
+ assertTrue("enable Wifi failed", enableWifi());
+ sleep(2 * SHORT_TIMEOUT, "interrupted while waiting for WPA_SUPPLICANT to start");
+ WifiInfo mConnection = mWifiManager.getConnectionInfo();
assertNotNull(mConnection);
- assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
+ assertTrue("wpa_supplicant is not started ", mWifiManager.pingSupplicant());
}
@Override
public void tearDown() throws Exception {
- log("tearDown()");
super.tearDown();
}
@@ -107,16 +96,16 @@
private void connectToWifi(WifiConfiguration config) {
// step 1: connect to the test access point
assertTrue("failed to associate with " + config.SSID,
- mAct.connectToWifiWithConfiguration(config));
+ connectToWifiWithConfiguration(config));
// step 2: verify Wifi state and network state;
assertTrue("failed to connect with " + config.SSID,
- mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.CONNECTED, ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// step 3: verify the current connected network is the given SSID
- assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
- assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+ assertNotNull("Wifi connection returns null", mWifiManager.getConnectionInfo());
+ assertTrue(config.SSID.contains(mWifiManager.getConnectionInfo().getSSID()));
}
private void sleep(long sometime, String errorMsg) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index de0298e..ad73ee1 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -16,35 +16,19 @@
package com.android.connectivitymanagertest.functional;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
-import android.R;
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Intent;
import android.content.Context;
-import android.content.res.Resources;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiConfiguration.Status;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.ConnectivityManager;
-import android.net.DhcpInfo;
-import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
import android.test.suitebuilder.annotation.LargeTest;
-import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
-import com.android.internal.util.AsyncChannel;
-
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -56,39 +40,25 @@
* -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
*/
public class WifiConnectionTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private static final String TAG = "WifiConnectionTest";
private static final boolean DEBUG = false;
private List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
- private ConnectivityManagerTestActivity mAct;
- private ConnectivityManagerTestRunner mRunner;
- private WifiManager mWifiManager = null;
- private Set<WifiConfiguration> enabledNetworks = null;
-
- public WifiConnectionTest() {
- super(ConnectivityManagerTestActivity.class);
- }
@Override
public void setUp() throws Exception {
super.setUp();
- mRunner = ((ConnectivityManagerTestRunner)getInstrumentation());
- mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
-
- mAct = getActivity();
-
- networks = mAct.loadNetworkConfigurations();
+ networks = loadNetworkConfigurations();
if (DEBUG) {
printNetworkConfigurations();
}
// enable Wifi and verify wpa_supplicant is started
- assertTrue("enable Wifi failed", mAct.enableWifi());
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "interrupted while waiting for WPA_SUPPLICANT to start");
- WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
+ assertTrue("enable Wifi failed", enableWifi());
+ sleep(2 * SHORT_TIMEOUT, "interrupted while waiting for WPA_SUPPLICANT to start");
+ WifiInfo mConnection = mWifiManager.getConnectionInfo();
assertNotNull(mConnection);
- assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
+ assertTrue("wpa_supplicant is not started ", mWifiManager.pingSupplicant());
}
private void printNetworkConfigurations() {
@@ -101,8 +71,7 @@
@Override
public void tearDown() throws Exception {
- log("tearDown()");
- mAct.removeConfiguredNetworksAndDisableWifi();
+ removeConfiguredNetworksAndDisableWifi();
super.tearDown();
}
@@ -114,20 +83,20 @@
private void connectToWifi(WifiConfiguration config) {
// step 1: connect to the test access point
assertTrue("failed to connect to " + config.SSID,
- mAct.connectToWifiWithConfiguration(config));
+ connectToWifiWithConfiguration(config));
// step 2: verify Wifi state and network state;
- assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.CONNECTED, ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// step 3: verify the current connected network is the given SSID
- assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
+ assertNotNull("Wifi connection returns null", mWifiManager.getConnectionInfo());
if (DEBUG) {
log("config.SSID = " + config.SSID);
- log("mAct.mWifiManager.getConnectionInfo.getSSID()" +
- mAct.mWifiManager.getConnectionInfo().getSSID());
+ log("mWifiManager.getConnectionInfo.getSSID()" +
+ mWifiManager.getConnectionInfo().getSSID());
}
- assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+ assertTrue(config.SSID.contains(mWifiManager.getConnectionInfo().getSSID()));
}
private void sleep(long sometime, String errorMsg) {
@@ -149,8 +118,7 @@
log("-- START Wi-Fi connection test to : " + ssid + " --");
connectToWifi(networks.get(i));
// wait for 2 minutes between wifi stop and start
- sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL,
- "interruped while connected to wifi");
+ sleep(WIFI_STOP_START_INTERVAL, "interruped while connected to wifi");
log("-- END Wi-Fi connection test to " + ssid + " -- ");
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index 60595fb..790ca38 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -18,19 +18,13 @@
import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
-import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiManager;
import android.os.Environment;
-import android.os.IPowerManager;
-import android.os.PowerManager;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -42,30 +36,24 @@
* Stress the wifi driver as access point.
*/
public class WifiApStress
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private final static String TAG = "WifiApStress";
private static String NETWORK_ID = "AndroidAPTest";
private static String PASSWD = "androidwifi";
private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
- private ConnectivityManagerTestActivity mAct;
private int iterations;
private BufferedWriter mOutputWriter = null;
private int mLastIteration = 0;
private boolean mWifiOnlyFlag;
- public WifiApStress() {
- super(ConnectivityManagerTestActivity.class);
- }
-
@Override
public void setUp() throws Exception {
super.setUp();
- mAct = getActivity();
ConnectivityManagerStressTestRunner mRunner =
(ConnectivityManagerStressTestRunner)getInstrumentation();
iterations = mRunner.mSoftapIterations;
mWifiOnlyFlag = mRunner.mWifiOnlyFlag;
- mAct.turnScreenOn();
+ turnScreenOn();
}
@Override
@@ -92,30 +80,28 @@
config.preSharedKey = PASSWD;
// If Wifi is enabled, disable it
- if (mAct.mWifiManager.isWifiEnabled()) {
- mAct.disableWifi();
+ if (mWifiManager.isWifiEnabled()) {
+ disableWifi();
}
int i;
for (i = 0; i < iterations; i++) {
Log.v(TAG, "iteration: " + i);
mLastIteration = i;
// enable Wifi tethering
- assertTrue(mAct.mWifiManager.setWifiApEnabled(config, true));
+ assertTrue(mWifiManager.setWifiApEnabled(config, true));
// Wait for wifi ap state to be ENABLED
- assertTrue(mAct.waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED,
- 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED, 2 * LONG_TIMEOUT));
// Wait for wifi tethering result
- assertEquals(ConnectivityManagerTestActivity.SUCCESS,
- mAct.waitForTetherStateChange(2*ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ assertEquals(SUCCESS, waitForTetherStateChange(2 * SHORT_TIMEOUT));
// Allow the wifi tethering to be enabled for 10 seconds
try {
- Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(2 * SHORT_TIMEOUT);
} catch (Exception e) {
fail("thread in sleep is interrupted");
}
- assertTrue("no uplink data connection after Wi-Fi tethering", mAct.pingTest(null));
+ assertTrue("no uplink data connection after Wi-Fi tethering", pingTest(null));
// Disable soft AP
- assertTrue(mAct.mWifiManager.setWifiApEnabled(config, false));
+ assertTrue(mWifiManager.setWifiApEnabled(config, false));
// Wait for 30 seconds until Wi-Fi tethering is stopped
try {
Thread.sleep(30 * 1000);
@@ -123,7 +109,7 @@
} catch (Exception e) {
fail("thread in sleep is interrupted");
}
- assertFalse("Wi-Fi AP disable failed", mAct.mWifiManager.isWifiApEnabled());
+ assertFalse("Wi-Fi AP disable failed", mWifiManager.isWifiApEnabled());
}
if (i == iterations) {
mLastIteration = iterations;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index e3c7cc4..04ce4b7 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -29,12 +29,11 @@
import android.os.PowerManager;
import android.provider.Settings;
import android.view.KeyEvent;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import java.io.BufferedWriter;
import java.io.File;
@@ -50,7 +49,7 @@
* -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner
*/
public class WifiStressTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private final static String TAG = "WifiStressTest";
/**
@@ -67,7 +66,6 @@
private final static long WIFI_SHUTDOWN_DELAY = 2 * 60 * 1000;
private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
- private ConnectivityManagerTestActivity mAct;
private int mReconnectIterations;
private int mWifiSleepTime;
private int mScanIterations;
@@ -77,15 +75,10 @@
private BufferedWriter mOutputWriter = null;
private boolean mWifiOnlyFlag;
- public WifiStressTest() {
- super(ConnectivityManagerTestActivity.class);
- }
-
@Override
public void setUp() throws Exception {
super.setUp();
- mAct = getActivity();
mRunner = (ConnectivityManagerStressTestRunner) getInstrumentation();
mReconnectIterations = mRunner.mReconnectIterations;
mSsid = mRunner.mReconnectSsid;
@@ -98,15 +91,14 @@
mPassword, mScanIterations, mWifiSleepTime));
mOutputWriter = new BufferedWriter(new FileWriter(new File(
Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
- mAct.turnScreenOn();
- if (!mAct.mWifiManager.isWifiEnabled()) {
+ turnScreenOn();
+ if (!mWifiManager.isWifiEnabled()) {
log("Enable wi-fi before stress tests.");
- if (!mAct.enableWifi()) {
+ if (!enableWifi()) {
tearDown();
fail("enable wifi failed.");
}
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "Interruped while waiting for wifi on");
+ sleep(SHORT_TIMEOUT, "Interruped while waiting for wifi on");
}
}
@@ -166,33 +158,32 @@
writeOutput(String.format("ssid appear %d out of %d scan iterations",
ssidAppearInScanResultsCount, i));
long startTime = System.currentTimeMillis();
- mAct.scanResultAvailable = false;
- assertTrue("start scan failed", mAct.mWifiManager.startScan());
+ scanResultAvailable = false;
+ assertTrue("start scan failed", mWifiManager.startScan());
while (true) {
if ((System.currentTimeMillis() - startTime) >
- ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT) {
- fail("Wifi scanning takes more than " +
- ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT + " ms");
+ WIFI_SCAN_TIMEOUT) {
+ fail("Wifi scanning takes more than " + WIFI_SCAN_TIMEOUT + " ms");
}
- synchronized(mAct) {
+ synchronized(this) {
try {
- mAct.wait(ConnectivityManagerTestActivity.WAIT_FOR_SCAN_RESULT);
+ wait(WAIT_FOR_SCAN_RESULT);
} catch (InterruptedException e) {
e.printStackTrace();
}
- if (mAct.scanResultAvailable) {
+ if (scanResultAvailable) {
long scanTime = (System.currentTimeMillis() - startTime);
scanTimeSum += scanTime;
break;
}
}
}
- if ((mAct.mWifiManager.getScanResults() == null) ||
- (mAct.mWifiManager.getScanResults().size() <= 0)) {
+ if ((mWifiManager.getScanResults() == null) ||
+ (mWifiManager.getScanResults().size() <= 0)) {
fail("Scan results are empty ");
}
- List<ScanResult> netList = mAct.mWifiManager.getScanResults();
+ List<ScanResult> netList = mWifiManager.getScanResults();
if (netList != null) {
log("size of scan result list: " + netList.size());
for (int s = 0; s < netList.size(); s++) {
@@ -244,13 +235,13 @@
config.proxySettings = ProxySettings.NONE;
assertTrue("Failed to connect to Wi-Fi network: " + mSsid,
- mAct.connectToWifiWithConfiguration(config));
- assertTrue(mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.SHORT_TIMEOUT));
- assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifiWithConfiguration(config));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+ SHORT_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
// Run ping test to verify the data connection
- assertTrue("Wi-Fi is connected, but no data connection.", mAct.pingTest(null));
+ assertTrue("Wi-Fi is connected, but no data connection.", pingTest(null));
int i;
long sum = 0;
@@ -263,33 +254,33 @@
writeOutput(String.format("iteration %d out of %d",
i, mReconnectIterations));
log("iteration: " + i);
- mAct.turnScreenOff();
+ turnScreenOff();
PowerManager pm =
(PowerManager)mRunner.getContext().getSystemService(Context.POWER_SERVICE);
assertFalse(pm.isScreenOn());
sleep(WIFI_IDLE_MS + WIFI_SHUTDOWN_DELAY, "Interruped while wait for wifi to be idle");
assertTrue("Wait for Wi-Fi to idle timeout",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- 6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+ 6 * SHORT_TIMEOUT));
if (!mWifiOnlyFlag) {
// use long timeout as the pppd startup may take several retries.
assertTrue("Wait for cellular connection timeout",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+ 2 * LONG_TIMEOUT));
}
sleep(mWifiSleepTime, "Interrupted while device is in sleep mode");
// Verify the wi-fi is still off and data connection is on
assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
- mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
+ mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
if (!mWifiOnlyFlag) {
assertEquals("Cellular connection is down", State.CONNECTED,
- mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
- assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
+ mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
+ assertTrue("Mobile is connected, but no data connection.", pingTest(null));
}
// Turn screen on again
- mAct.turnScreenOn();
+ turnScreenOn();
// Wait for 2 seconds for the lock screen
sleep(2 * 1000, "wait 2 seconds for lock screen");
// Disable lock screen by inject menu key event
@@ -298,16 +289,16 @@
// Measure the time for Wi-Fi to get connected
long startTime = System.currentTimeMillis();
assertTrue("Wait for Wi-Fi enable timeout after wake up",
- mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+ SHORT_TIMEOUT));
assertTrue("Wait for Wi-Fi connection timeout after wake up",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
long connectionTime = System.currentTimeMillis() - startTime;
sum += connectionTime;
log("average reconnection time is: " + sum/(i+1));
- assertTrue("Reconnect to Wi-Fi network, but no data connection.", mAct.pingTest(null));
+ assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null));
}
if (i == mReconnectIterations) {
writeOutput(String.format("iteration %d out of %d",
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
index e44023b..7a9bc78 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
@@ -20,9 +20,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Context;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiConfiguration;
@@ -33,11 +30,8 @@
import android.test.suitebuilder.annotation.LargeTest;
import android.test.AndroidTestCase;
-import java.util.ArrayList;
import java.util.List;
-import android.util.Log;
-
/**
* Test wifi client
*/
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
index 3f43e48..f202862 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
@@ -16,13 +16,7 @@
package com.android.connectivitymanagertest.unit;
-import android.content.BroadcastReceiver;
-import android.content.Intent;
import android.content.Context;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
-import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -30,8 +24,6 @@
import android.test.suitebuilder.annotation.LargeTest;
import android.test.AndroidTestCase;
-import java.util.ArrayList;
-
import android.util.Log;
/**
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index ebecf2e3..a2e9ae8 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -83,8 +83,8 @@
mImageReaderLock.lock();
try {
- mImageReader = new ImageReader(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
- mImageReader.setImageAvailableListener(mImageListener, mHandler);
+ mImageReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
+ mImageReader.setOnImageAvailableListener(mImageListener, mHandler);
mSurface = mImageReader.getSurface();
} finally {
mImageReaderLock.unlock();
@@ -409,19 +409,11 @@
}
Log.d(TAG, "New image available from virtual display.");
- Image image = reader.getNextImage();
+
+ // Get the latest buffer.
+ Image image = reader.acquireLatestImage();
if (image != null) {
try {
- // Get the latest buffer.
- for (;;) {
- Image nextImage = reader.getNextImage();
- if (nextImage == null) {
- break;
- }
- reader.releaseImage(image);
- image = nextImage;
- }
-
// Scan for colors.
int color = scanImage(image);
synchronized (this) {
@@ -431,7 +423,7 @@
}
}
} finally {
- reader.releaseImage(image);
+ image.close();
}
}
} finally {
diff --git a/docs/html/google/play/billing/gp-purchase-status-api.jd b/docs/html/google/play/billing/gp-purchase-status-api.jd
index c5b8461..25ef28b 100644
--- a/docs/html/google/play/billing/gp-purchase-status-api.jd
+++ b/docs/html/google/play/billing/gp-purchase-status-api.jd
@@ -88,7 +88,7 @@
<h3 id="quota">Quota</h3>
<p>Applications using the Google Play Android Developer API are limited to an
-initial courtesy usage quota of <strong>15000 requests per day</strong> (per
+initial courtesy usage quota of <strong>200,000 requests per day</strong> (per
application). This should provide enough access for normal
subscription-validation needs, assuming that you follow the recommendation in
this section.</p>
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index 607d16e..14a1682 100644
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -10,6 +10,11 @@
<ol>
<li><a href="#writing-an-rs-kernel">Writing a RenderScript Kernel</a></li>
+ <li><a href="#access-rs-apis">Accessing RenderScript Java APIs</a>
+ <ol>
+ <li><a href="#ide-setup">Setting Up Your Development Environment</a></li>
+ </ol>
+ </li>
<li><a href="#using-rs-from-java">Using RenderScript from Java Code</a></li>
</ol>
@@ -144,9 +149,85 @@
beneficial on some architectures due to additional optimizations only available with relaxed
precision (such as SIMD CPU instructions).</p>
+
+<h2 id="access-rs-apis">Accessing RenderScript Java APIs</h2>
+
+<p>When developing an Android application that uses RenderScript, you can access its Java API in
+ one of two ways. The APIs are available in the {@link android.renderscript} package
+ on devices running Android 3.0 (API level 11) and higher. These are the original APIs for
+ RenderScript. The APIs are also available as a Support Library in the
+ {@link android.support.v8.renderscript} package, which allow you to use them on devices running
+ Android 2.2 (API level 8) and higher.</p>
+
+<p>We strongly recommend using the Support Library APIs for accessing RenderScript because they
+ include the latest improvements to the RenderScript compute framework and provide a wider range
+ of device compatibility. Using the RenderScript APIs in the Support Library requires specific
+ setup procedures for your development environment, which is described in the next section.</p>
+
+
+<h3 id="ide-setup">Using the RenderScript Support Library APIs</h3>
+
+<p>In order to use the Support Library RenderScript APIs, you must configure your development
+ environment to be able to access them. The following Android SDK tools are required for using
+ these APIs:</p>
+
+<ul>
+ <li>Android SDK Tools revision 22.2 or higher</li>
+ <li>Android SDK Build-tools revision 18.1.0 or higher</li>
+</ul>
+
+<p>You can check and update the installed version of these tools in the
+ <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.</p>
+
+<p class="note">
+ <strong>Note:</strong> Use of Support Library RenderScript APIs is not currently supported with
+ Android Studio or Gradle-based builds.
+</p>
+
+<p>To use the Support Library RenderScript APIs in Eclipse:</p>
+
+<ol>
+ <li>Make sure you have the required Android SDK version and Build Tools version installed.</li>
+ <li>Open the {@code project.properties} file in the root folder of your application project.</li>
+ <li>Add the following lines to the file:
+<pre>
+renderscript.target=18
+renderscript.support.mode=true
+sdk.buildtools=18.1.0
+</pre>
+ </li>
+ <li>In your application classes that use RenderScript, add an import for the Support Library
+ classes:
+<pre>
+import android.support.v8.renderscript.*;
+</pre>
+ </li>
+</ol>
+
+<p>The {@code project.properties} settings listed above control specific behavior in the Android
+ build process:</p>
+
+<ul>
+ <li>{@code renderscript.target} - Specifies the bytecode version to be generated. We
+ recommend you set this value the highest available API level and set {@code
+ renderscript.support.mode} to {@code true}. Valid values for this setting are any integer value
+ from 11 to the most recently released API level. If your minimum SDK version specified in your
+ application manifest is set to a higher value, this value is ignored and the target value is set
+ to the minimum SDK version.</li>
+ <li>{@code renderscript.support.mode} - Specifies that the generated bytecode should fall
+ back to a compatible version if the device it is running on does not support the target version.
+ </li>
+ <li>{@code sdk.buildtools} - The version of the Android SDK build tools to use. This value
+ should be set to 18.1.0 or higher. If this option is not specified, the highest installed build
+ tools version is used. You should always set this value to ensure the consistency of builds
+ across development machines with different configurations.</li>
+</ul>
+
+
<h2 id="using-rs-from-java">Using RenderScript from Java Code</h2>
-<p>Using RenderScript from Java code relies on the {@link android.renderscript} APIs. Most
+<p>Using RenderScript from Java code relies on the API classes located in the
+{@link android.renderscript} or the {@link android.support.v8.renderscript} package. Most
applications follow the same basic usage patterns:</p>
<ol>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 4ea3752..0581435 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,43 +5,43 @@
page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
-sdk.linux32_bundle_download=adt-bundle-linux-x86-20130729.zip
-sdk.linux32_bundle_bytes=457716139
-sdk.linux32_bundle_checksum=b3686d10dc1cbceba1074404d4386283
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20130911.zip
+sdk.linux32_bundle_bytes=474916528
+sdk.linux32_bundle_checksum=7eacc7124299ea99a8fa15c59123540f
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130729.zip
-sdk.linux64_bundle_bytes=458006784
-sdk.linux64_bundle_checksum=1fabcc3f772ba8b2fc194d6e0449da17
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130911.zip
+sdk.linux64_bundle_bytes=475207785
+sdk.linux64_bundle_checksum=daa5794a27be7c7fa708c3d28833b0d3
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130729.zip
-sdk.mac64_bundle_bytes=428792424
-sdk.mac64_bundle_checksum=6c42b9966abcfa8a75c0ee83d0d95882
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130911.zip
+sdk.mac64_bundle_bytes=448575446
+sdk.mac64_bundle_checksum=a1e0cbcc820ae734cfdf439c40811b4c
-sdk.win32_bundle_download=adt-bundle-windows-x86-20130729.zip
-sdk.win32_bundle_bytes=463931746
-sdk.win32_bundle_checksum=51faf4e5fdf9c5b4a176179a99ce3511
+sdk.win32_bundle_download=adt-bundle-windows-x86-20130911.zip
+sdk.win32_bundle_bytes=481794820
+sdk.win32_bundle_checksum=88a2f4f242aac44f4b1c53e6eccc8710
-sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130729.zip
-sdk.win64_bundle_bytes=464064756
-sdk.win64_bundle_checksum=e8f05c1fddb8e609e880de23113c7426
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130911.zip
+sdk.win64_bundle_bytes=481927327
+sdk.win64_bundle_checksum=e3fa9b7e38af9ed9ac0e99fce3c7026c
-sdk.linux_download=android-sdk_r22.0.5-linux.tgz
-sdk.linux_bytes=105641005
-sdk.linux_checksum=8201b10c21510f082c54f58a9bb082c8
+sdk.linux_download=android-sdk_r22.2-linux.tgz
+sdk.linux_bytes=100909403
+sdk.linux_checksum=2a3776839e823ba9acb7a87a3fe26e02
-sdk.mac_download=android-sdk_r22.0.5-macosx.zip
-sdk.mac_bytes=77225724
-sdk.mac_checksum=94f3cbe896c332b94ee0408ae610a4b8
+sdk.mac_download=android-sdk_r22.2-macosx.zip
+sdk.mac_bytes=74857114
+sdk.mac_checksum=9dfef6404e2f842c433073796aed8b7d
-sdk.win_download=android-sdk_r22.0.5-windows.zip
-sdk.win_bytes=113510621
-sdk.win_checksum=30695dffc41e0d7cf9ff948ab0c48920
+sdk.win_download=android-sdk_r22.2-windows.zip
+sdk.win_bytes=108790714
+sdk.win_checksum=1ac4c104378cd53049daa6c4458ec544
-sdk.win_installer=installer_r22.0.5-windows.exe
-sdk.win_installer_bytes=93505782
-sdk.win_installer_checksum=940849be19ac6151e3e35c8706c81d86
+sdk.win_installer=installer_r22.2-windows.exe
+sdk.win_installer_bytes=88788974
+sdk.win_installer_checksum=e5503fa059297d2b18475c086ac6e80c
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index bdc07d0..e038d20 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
page.title=Installing the Eclipse Plugin
-adt.zip.version=22.0.5
-adt.zip.download=ADT-22.0.5.zip
-adt.zip.bytes=16839757
-adt.zip.checksum=1097fccf32063e3638a9d27aa0f295ca
+adt.zip.version=22.2.0
+adt.zip.download=ADT-22.2.0.zip
+adt.zip.bytes=14474195
+adt.zip.checksum=52892c9e3b1ad2d1e6edd50e48b2a127
@jd:body
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index e9c514e..151707a 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,44 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>ADT 22.2</a> <em>(September 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.2</a>.
+ If you haven't already installed SDK Tools r22.2 into your SDK, use the
+ Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Updated build tools to allow use of RenderScript on older versions of Android
+ using new features in the
+ <a href="{@docRoot}tools/support-library/features.html#v8">Support Library</a>.</li>
+ <li>Reverted signing changes that sometimes trigger a signing verification problem on older
+ platforms.</li>
+ <li>Fixed problem with gradle export function for the Windows platform.</li>
+ </ul>
+ </dd>
+
+</dl>
+</div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>ADT 22.0.5</a> <em>(July 2013)</em>
</p>
@@ -78,7 +116,7 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed Renderscript compilation issue for Windows platforms.</li>
+ <li>Fixed RenderScript compilation issue for Windows platforms.</li>
<li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> report generation
in the Monitor and DDMS perspectives.</li>
</ul>
@@ -113,7 +151,7 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed problem with compiling Renderscript code.</li>
+ <li>Fixed problem with compiling RenderScript code.</li>
<li>Improved Gradle export with better workflow and error reporting.</li>
<li>Improved Gradle multi-module export feature.</li>
<li>Updated build logic to force exporting of the classpath containers unless you are using
@@ -1005,7 +1043,7 @@
<dt>Bug fixes:</dt>
<dd>
<ul>
- <li>Fixed build issue when using Renderscript in projects that target API levels 11-13
+ <li>Fixed build issue when using RenderScript in projects that target API levels 11-13
(<a href="http://code.google.com/p/android/issues/detail?id=21006">Issue 21006</a>).</li>
<li>Fixed issue when creating projects from existing source code.</li>
<li>Fixed issues in the SDK Manager
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 4aef8a0..e8c4717 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -30,6 +30,54 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 22.2</a> <em>(September 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 16 or later.</li>
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
+ designed for use with ADT 22.2 and later. If you haven't already, update your
+ <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.2.</li>
+ <li>If you are developing outside Eclipse, you must have
+ <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Updated build tools to allow use of RenderScript on older versions of Android
+ using new features in the
+ <a href="{@docRoot}tools/support-library/features.html#v8">Support Library</a>.</li>
+ <li>Moved the Systrace tool to the {@code >sdk</platform-tools/} directory. </li>
+ <li>Modified <a href="{@docRoot}tools/help/gltracer.html">Tracer for OpenGL ES</a> to
+ support OpenGL ES 3.0.</li>
+ <li>Lint
+ <ul>
+ <li>Fixed problem with lint not detecting custom namespaces.
+ (<a href="http://b.android.com/55673">Issue 55673</a>)</li>
+ <li>Fixed problem with the XML report including invalid characters.
+ (<a href="http://b.android.com/56205">Issue 56205</a>)</li>
+ <li>Fixed command-line execution of lint to work in headless mode to support execution
+ by build servers. (<a href="http://b.android.com/55820">Issue 55820</a>)</li>
+ </ul>
+ </li>
+ <li>Improved support for path names with spaces in the Windows command-line tools.</li>
+ </ul>
+ </dd>
+ </dl>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>SDK Tools, Revision 22.0.5</a> <em>(July 2013)</em>
</p>
@@ -55,10 +103,10 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed Renderscript compilation issue for Windows platforms with ant.</li>
+ <li>Fixed RenderScript compilation issue for Windows platforms with ant.</li>
<li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> to work with the
Android 4.3 platform image.</li>
- <li>Fixed packaging of Renderscript compiler.</li>
+ <li>Fixed packaging of RenderScript compiler.</li>
<li>Build tools 18.0.0 is obsolete and 18.0.1 should be used instead.</li>
</ul>
</dd>
@@ -95,7 +143,7 @@
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed problem with compiling Renderscript code.</li>
+ <li>Fixed problem with compiling RenderScript code.</li>
</ul>
</dd>
</dl>
@@ -274,17 +322,17 @@
</ul>
</li>
- <li>Renderscript
+ <li>RenderScript
<ul>
<li>Added support for
<a href="{@docRoot}guide/topics/renderscript/compute.html#filterscript">Filterscript</a>
compilation.</li>
- <li>Added new project setting to control the Renderscript compilation target separately
+ <li>Added new project setting to control the RenderScript compilation target separately
from an Android project. Adding the following line to a {@code project.properties}
- file causes Renderscript code to be compiled for Android API Level 17, while the
+ file causes RenderScript code to be compiled for Android API Level 17, while the
containing application can target a different (lower) API level:
<pre>renderscript.target = 17</pre>
- Previously, the Renderscript compilation target was tied to the
+ Previously, the RenderScript compilation target was tied to the
{@code android:minSdkVersion} setting in the manifest.
(<a href="http://code.google.com/p/android/issues/detail?id=40487">Issue 40487</a>)
</li>
@@ -483,7 +531,7 @@
<li>Improved resize algorithm for better rendering on scaled emulator windows.</li>
<li>Fixed a bug in the {@code lint} check for unprotected broadcast receivers to ignore
unprotected receivers for default Android actions.</li>
- <li>Fixed build issue for projects using Renderscript.</li>
+ <li>Fixed build issue for projects using RenderScript.</li>
<li>Fixed memory leak in the emulator.</li>
</ul>
</dd>
@@ -823,7 +871,7 @@
<li>Fixed emulator crash on Linux due to improper webcam detection
(<a href="http://code.google.com/p/android/issues/detail?id=20952">Issue 20952</a>).</li>
<li>Fixed emulator issue when using the <code>-wipe-data</code> argument.</li>
- <li>Fixed build issue when using Renderscript in projects that target API levels 11-13
+ <li>Fixed build issue when using RenderScript in projects that target API levels 11-13
(<a href="http://code.google.com/p/android/issues/detail?id=21006">Issue 21006</a>).</li>
<li>Fixed issue when creating an AVD using the GoogleTV addon
(<a href="http://code.google.com/p/android/issues/detail?id=20963">Issue 20963</a>).</li>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 8d25d96..65148bf 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -15,6 +15,7 @@
<li><a href="#v7-mediarouter">v7 mediarouter library</a></li>
</ol>
</li>
+ <li><a href="#v8">v8 Support Library</a></li>
<li><a href="#v13">v13 Support Library</a></li>
</ol>
@@ -252,7 +253,7 @@
where "18.0.0" is the minimum revision at which the library is available. For example:</p>
<pre>
-com.android.support:support-v7-mediarouter:18.0.0
+com.android.support:mediarouter-v7:18.0.+
</pre>
<p class="caution">The v7 mediarouter library APIs introduced in Support Library
@@ -262,6 +263,24 @@
developer preview</a>. </p>
+<h2 id="v8">v8 Support Library</h2>
+
+<p>This library is designed to be used with Android (API level 8) and higher. It adds support for
+ the <a href="{@docRoot}guide/topics/renderscript/compute.html">RenderScript</a> computation
+ framework. These APIs are included in the {@link android.support.v8.renderscript} package. You
+ should be aware that the steps for including these APIs in your application is <em>very
+ different</em> from other support library APIs. For more information about using these APIs
+ in your application, see the
+ <a href="{@docRoot}guide/topics/renderscript/compute.html#access-rs-apis">RenderScript</a>
+ developer guide.</p>
+
+<p class="note">
+ <strong>Note:</strong> Use of RenderScript with the support library is supported with the Android
+ Eclipse plugin and Ant build tools. It is <em>not currently</em> supported with Android Studio or
+ Gradle-based builds.
+</p>
+
+
<h2 id="v13">v13 Support Library</h2>
<p>This library is designed to be used for Android 3.2 (API level 13) and higher. It adds support
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 06c7a3f..4ee8c12 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -58,6 +58,7 @@
<p>This section provides details about the Support Library package releases.</p>
+
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 9f442f5..a346e17 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -16,20 +16,19 @@
package android.media;
-import android.graphics.ImageFormat;
import java.nio.ByteBuffer;
import java.lang.AutoCloseable;
/**
* <p>A single complete image buffer to use with a media source such as a
* {@link MediaCodec} or a
- * {@link android.hardware.camera2.CameraDevice}.</p>
+ * {@link android.hardware.camera2.CameraDevice CameraDevice}.</p>
*
* <p>This class allows for efficient direct application access to the pixel
* data of the Image through one or more
* {@link java.nio.ByteBuffer ByteBuffers}. Each buffer is encapsulated in a
* {@link Plane} that describes the layout of the pixel data in that plane. Due
- * to this direct access, and unlike the {@link android.graphics.Bitmap} class,
+ * to this direct access, and unlike the {@link android.graphics.Bitmap Bitmap} class,
* Images are not directly usable as as UI resources.</p>
*
* <p>Since Images are often directly produced or consumed by hardware
@@ -40,19 +39,28 @@
* from various media sources, not closing old Image objects will prevent the
* availability of new Images once
* {@link ImageReader#getMaxImages the maximum outstanding image count} is
- * reached.</p>
+ * reached. When this happens, the function acquiring new Images will typically
+ * throw an {@link IllegalStateException}.</p>
*
* @see ImageReader
*/
-public interface Image extends AutoCloseable {
+public abstract class Image implements AutoCloseable {
+ /**
+ * @hide
+ */
+ protected Image() {
+ }
+
/**
* Get the format for this image. This format determines the number of
* ByteBuffers needed to represent the image, and the general layout of the
* pixel data in each in ByteBuffer.
*
+ * <p>
* The format is one of the values from
- * {@link android.graphics.ImageFormat}. The mapping between the formats and
- * the planes is as follows:
+ * {@link android.graphics.ImageFormat ImageFormat}. The mapping between the
+ * formats and the planes is as follows:
+ * </p>
*
* <table>
* <tr>
@@ -61,13 +69,14 @@
* <th>Layout details</th>
* </tr>
* <tr>
- * <td>{@link android.graphics.ImageFormat#JPEG}</td>
+ * <td>{@link android.graphics.ImageFormat#JPEG JPEG}</td>
* <td>1</td>
* <td>Compressed data, so row and pixel strides are 0. To uncompress, use
- * {@link android.graphics.BitmapFactory#decodeByteArray}.</td>
+ * {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
+ * </td>
* </tr>
* <tr>
- * <td>{@link android.graphics.ImageFormat#YUV_420_888}</td>
+ * <td>{@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}</td>
* <td>3</td>
* <td>A luminance plane followed by the Cb and Cr chroma planes.
* The chroma planes have half the width and height of the luminance
@@ -75,53 +84,60 @@
* Each plane has its own row stride and pixel stride.</td>
* </tr>
* <tr>
- * <td>{@link android.graphics.ImageFormat#RAW_SENSOR}</td>
+ * <td>{@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}</td>
* <td>1</td>
* <td>A single plane of raw sensor image data, with 16 bits per color
* sample. The details of the layout need to be queried from the source of
* the raw sensor data, such as
- * {@link android.hardware.camera2.CameraDevice}.
+ * {@link android.hardware.camera2.CameraDevice CameraDevice}.
* </td>
* </tr>
* </table>
*
* @see android.graphics.ImageFormat
*/
- public int getFormat();
+ public abstract int getFormat();
/**
* The width of the image in pixels. For formats where some color channels
* are subsampled, this is the width of the largest-resolution plane.
*/
- public int getWidth();
+ public abstract int getWidth();
/**
* The height of the image in pixels. For formats where some color channels
* are subsampled, this is the height of the largest-resolution plane.
*/
- public int getHeight();
+ public abstract int getHeight();
/**
- * Get the timestamp associated with this frame. The timestamp is measured
- * in nanoseconds, and is monotonically increasing. However, the zero point
- * and whether the timestamp can be compared against other sources of time
- * or images depend on the source of this image.
+ * Get the timestamp associated with this frame.
+ * <p>
+ * The timestamp is measured in nanoseconds, and is monotonically
+ * increasing. However, the zero point and whether the timestamp can be
+ * compared against other sources of time or images depend on the source of
+ * this image.
+ * </p>
*/
- public long getTimestamp();
+ public abstract long getTimestamp();
/**
* Get the array of pixel planes for this Image. The number of planes is
* determined by the format of the Image.
*/
- public Plane[] getPlanes();
+ public abstract Plane[] getPlanes();
/**
- * Free up this frame for reuse. After calling this method, calling any
- * methods on this Image will result in an IllegalStateException, and
- * attempting to read from ByteBuffers returned by an earlier
- * {@code Plane#getBuffer} call will have undefined behavior.
+ * Free up this frame for reuse.
+ * <p>
+ * After calling this method, calling any methods on this {@code Image} will
+ * result in an {@link IllegalStateException}, and attempting to read from
+ * {@link ByteBuffer ByteBuffers} returned by an earlier
+ * {@link Plane#getBuffer} call will have undefined behavior.
+ * </p>
*/
- public void close();
+ @Override
+ public abstract void close();
/**
* <p>A single color plane of image data.</p>
@@ -134,29 +150,41 @@
*
* @see #getFormat
*/
- public interface Plane {
+ public static abstract class Plane {
/**
- * <p>The row stride for this color plane, in bytes.
+ * @hide
+ */
+ protected Plane() {
+ }
+
+ /**
+ * <p>The row stride for this color plane, in bytes.</p>
*
* <p>This is the distance between the start of two consecutive rows of
- * pixels in the image.</p>
+ * pixels in the image. The row stride is always greater than 0.</p>
*/
- public int getRowStride();
+ public abstract int getRowStride();
/**
* <p>The distance between adjacent pixel samples, in bytes.</p>
*
* <p>This is the distance between two consecutive pixel values in a row
* of pixels. It may be larger than the size of a single pixel to
- * account for interleaved image data or padded formats.</p>
+ * account for interleaved image data or padded formats.
+ * The pixel stride is always greater than 0.</p>
*/
- public int getPixelStride();
+ public abstract int getPixelStride();
/**
- * <p>Get a set of direct {@link java.nio.ByteBuffer byte buffers}
+ * <p>Get a direct {@link java.nio.ByteBuffer ByteBuffer}
* containing the frame data.</p>
*
+ * <p>In particular, the buffer returned will always have
+ * {@link java.nio.ByteBuffer#isDirect isDirect} return {@code true}, so
+ * the underlying data could be mapped as a pointer in JNI without doing
+ * any copies with {@code GetDirectBufferAddress}.</p>
+ *
* @return the byte buffer containing the image data for this plane.
*/
- public ByteBuffer getBuffer();
+ public abstract ByteBuffer getBuffer();
}
}
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index b14a899..aee8362 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -40,41 +40,67 @@
* <p>The image data is encapsulated in {@link Image} objects, and multiple such
* objects can be accessed at the same time, up to the number specified by the
* {@code maxImages} constructor parameter. New images sent to an ImageReader
- * through its Surface are queued until accessed through the
- * {@link #getNextImage} call. Due to memory limits, an image source will
+ * through its {@link Surface} are queued until accessed through the {@link #acquireLatestImage}
+ * or {@link #acquireNextImage} call. Due to memory limits, an image source will
* eventually stall or drop Images in trying to render to the Surface if the
* ImageReader does not obtain and release Images at a rate equal to the
* production rate.</p>
*/
-public final class ImageReader implements AutoCloseable {
+public class ImageReader implements AutoCloseable {
+
+ /**
+ * Returned by nativeImageSetup when acquiring the image was successful.
+ */
+ private static final int ACQUIRE_SUCCESS = 0;
+ /**
+ * Returned by nativeImageSetup when we couldn't acquire the buffer,
+ * because there were no buffers available to acquire.
+ */
+ private static final int ACQUIRE_NO_BUFS = 1;
+ /**
+ * Returned by nativeImageSetup when we couldn't acquire the buffer
+ * because the consumer has already acquired {@maxImages} and cannot
+ * acquire more than that.
+ */
+ private static final int ACQUIRE_MAX_IMAGES = 2;
/**
* <p>Create a new reader for images of the desired size and format.</p>
*
- * <p>The maxImages parameter determines the maximum number of {@link Image}
- * objects that can be be acquired from the ImageReader
+ * <p>The {@code maxImages} parameter determines the maximum number of {@link Image}
+ * objects that can be be acquired from the {@code ImageReader}
* simultaneously. Requesting more buffers will use up more memory, so it is
* important to use only the minimum number necessary for the use case.</p>
*
* <p>The valid sizes and formats depend on the source of the image
* data.</p>
*
- * @param width the width in pixels of the Images that this reader will
- * produce.
- * @param height the height in pixels of the Images that this reader will
- * produce.
- * @param format the format of the Image that this reader will produce. This
- * must be one of the {@link android.graphics.ImageFormat} or
- * {@link android.graphics.PixelFormat} constants.
- * @param maxImages the maximum number of images the user will want to
- * access simultaneously. This should be as small as possible to limit
- * memory use. Once maxImages Images are obtained by the user, one of them
- * has to be released before a new Image will become available for access
- * through getNextImage(). Must be greater than 0.
+ * @param width
+ * The width in pixels of the Images that this reader will produce.
+ * @param height
+ * The height in pixels of the Images that this reader will produce.
+ * @param format
+ * The format of the Image that this reader will produce. This
+ * must be one of the {@link android.graphics.ImageFormat} or
+ * {@link android.graphics.PixelFormat} constants.
+ * @param maxImages
+ * The maximum number of images the user will want to
+ * access simultaneously. This should be as small as possible to limit
+ * memory use. Once maxImages Images are obtained by the user, one of them
+ * has to be released before a new Image will become available for access
+ * through {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
+ * Must be greater than 0.
*
* @see Image
*/
- public ImageReader(int width, int height, int format, int maxImages) {
+ public static ImageReader newInstance(int width, int height, int format, int maxImages) {
+ return new ImageReader(width, height, format, maxImages);
+ }
+
+ /**
+ * @hide
+ */
+ protected ImageReader(int width, int height, int format, int maxImages) {
mWidth = width;
mHeight = height;
mFormat = format;
@@ -96,33 +122,79 @@
mSurface = nativeGetSurface();
}
+ /**
+ * The width of each {@link Image}, in pixels.
+ *
+ * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
+ * {@link #acquireNextImage}) will have the same dimensions as specified in
+ * {@link #newInstance}.</p>
+ *
+ * @return the width of an Image
+ */
public int getWidth() {
return mWidth;
}
+ /**
+ * The height of each {@link Image}, in pixels.
+ *
+ * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
+ * {@link #acquireNextImage}) will have the same dimensions as specified in
+ * {@link #newInstance}.</p>
+ *
+ * @return the height of an Image
+ */
public int getHeight() {
return mHeight;
}
+ /**
+ * The {@link ImageFormat image format} of each Image.
+ *
+ * <p>ImageReader guarantees that all {@link Image Images} acquired from ImageReader
+ * (for example, with {@link #acquireNextImage}) will have the same format as specified in
+ * {@link #newInstance}.</p>
+ *
+ * @return the format of an Image
+ *
+ * @see ImageFormat
+ */
public int getImageFormat() {
return mFormat;
}
+ /**
+ * Maximum number of images that can be acquired from the ImageReader by any time (for example,
+ * with {@link #acquireNextImage}).
+ *
+ * <p>An image is considered acquired after it's returned by a function from ImageReader, and
+ * until the Image is {@link Image#close closed} to release the image back to the ImageReader.
+ * </p>
+ *
+ * <p>Attempting to acquire more than {@code maxImages} concurrently will result in the
+ * acquire function throwing a {@link IllegalStateException}. Furthermore,
+ * while the max number of images have been acquired by the ImageReader user, the producer
+ * enqueueing additional images may stall until at least one image has been released. </p>
+ *
+ * @return Maximum number of images for this ImageReader.
+ *
+ * @see Image#close
+ */
public int getMaxImages() {
return mMaxImages;
}
/**
- * <p>Get a Surface that can be used to produce Images for this
- * ImageReader.</p>
+ * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
+ * {@code ImageReader}.</p>
*
- * <p>Until valid image data is rendered into this Surface, the
- * {@link #getNextImage} method will return {@code null}. Only one source
+ * <p>Until valid image data is rendered into this {@link Surface}, the
+ * {@link #acquireNextImage} method will return {@code null}. Only one source
* can be producing data into this Surface at the same time, although the
- * same Surface can be reused with a different API once the first source is
- * disconnected from the Surface.</p>
+ * same {@link Surface} can be reused with a different API once the first source is
+ * disconnected from the {@link Surface}.</p>
*
- * @return A Surface to use for a drawing target for various APIs.
+ * @return A {@link Surface} to use for a drawing target for various APIs.
*/
public Surface getSurface() {
return mSurface;
@@ -130,41 +202,154 @@
/**
* <p>
- * Get the next Image from the ImageReader's queue. Returns {@code null} if
- * no new image is available.
+ * Acquire the latest {@link Image} from the ImageReader's queue, dropping older
+ * {@link Image images}. Returns {@code null} if no new image is available.
* </p>
* <p>
- * This operation will fail by throwing an
- * {@link Surface.OutOfResourcesException OutOfResourcesException} if too
- * many images have been acquired with {@link #getNextImage}. In particular
- * a sequence of {@link #getNextImage} calls greater than {@link #getMaxImages}
- * without calling {@link Image#close} or {@link #releaseImage} in-between
- * will exhaust the underlying queue. At such a time,
- * {@link Surface.OutOfResourcesException OutOfResourcesException} will be
- * thrown until more images are released with {@link Image#close} or
- * {@link #releaseImage}.
+ * This operation will acquire all the images possible from the ImageReader,
+ * but {@link #close} all images that aren't the latest. This function is
+ * recommended to use over {@link #acquireNextImage} for most use-cases, as it's
+ * more suited for real-time processing.
+ * </p>
+ * <p>
+ * Note that {@link #getMaxImages maxImages} should be at least 2 for
+ * {@link #acquireLatestImage} to be any different than {@link #acquireNextImage} -
+ * discarding all-but-the-newest {@link Image} requires temporarily acquiring two
+ * {@link Image Images} at once. Or more generally, calling {@link #acquireLatestImage}
+ * with less than two images of margin, that is
+ * {@code (maxImages - currentAcquiredImages < 2)} will not discard as expected.
+ * </p>
+ * <p>
+ * This operation will fail by throwing an {@link IllegalStateException} if
+ * {@code maxImages} have been acquired with {@link #acquireLatestImage} or
+ * {@link #acquireNextImage}. In particular a sequence of {@link #acquireLatestImage}
+ * calls greater than {@link #getMaxImages} without calling {@link Image#close} in-between
+ * will exhaust the underlying queue. At such a time, {@link IllegalStateException}
+ * will be thrown until more images are
+ * released with {@link Image#close}.
* </p>
*
- * @return a new frame of image data, or {@code null} if no image data is
- * available.
- * @throws Surface.OutOfResourcesException if too many images are currently
- * acquired
+ * @return latest frame of image data, or {@code null} if no image data is available.
+ * @throws IllegalStateException if too many images are currently acquired
*/
- public Image getNextImage() {
- SurfaceImage si = new SurfaceImage();
- if (nativeImageSetup(si)) {
- // create SurfacePlane objects
- si.createSurfacePlanes();
- si.setImageValid(true);
- return si;
+ public Image acquireLatestImage() {
+ Image image = acquireNextImage();
+ if (image == null) {
+ return null;
}
- return null;
+ try {
+ for (;;) {
+ Image next = acquireNextImageNoThrowISE();
+ if (next == null) {
+ Image result = image;
+ image = null;
+ return result;
+ }
+ image.close();
+ image = next;
+ }
+ } finally {
+ if (image != null) {
+ image.close();
+ }
+ }
+ }
+
+ /**
+ * Don't throw IllegalStateException if there are too many images acquired.
+ *
+ * @return Image if acquiring succeeded, or null otherwise.
+ *
+ * @hide
+ */
+ public Image acquireNextImageNoThrowISE() {
+ SurfaceImage si = new SurfaceImage();
+ return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
+ }
+
+ /**
+ * Attempts to acquire the next image from the underlying native implementation.
+ *
+ * <p>
+ * Note that unexpected failures will throw at the JNI level.
+ * </p>
+ *
+ * @param si A blank SurfaceImage.
+ * @return One of the {@code ACQUIRE_*} codes that determine success or failure.
+ *
+ * @see #ACQUIRE_MAX_IMAGES
+ * @see #ACQUIRE_NO_BUFS
+ * @see #ACQUIRE_SUCCESS
+ */
+ private int acquireNextSurfaceImage(SurfaceImage si) {
+
+ int status = nativeImageSetup(si);
+
+ switch (status) {
+ case ACQUIRE_SUCCESS:
+ si.createSurfacePlanes();
+ si.setImageValid(true);
+ case ACQUIRE_NO_BUFS:
+ case ACQUIRE_MAX_IMAGES:
+ break;
+ default:
+ throw new AssertionError("Unknown nativeImageSetup return code " + status);
+ }
+
+ return status;
+ }
+
+ /**
+ * <p>
+ * Acquire the next Image from the ImageReader's queue. Returns {@code null} if
+ * no new image is available.
+ * </p>
+ *
+ * <p><i>Warning:</i> Consider using {@link #acquireLatestImage()} instead, as it will
+ * automatically release older images, and allow slower-running processing routines to catch
+ * up to the newest frame. Usage of {@link #acquireNextImage} is recommended for
+ * batch/background processing. Incorrectly using this function can cause images to appear
+ * with an ever-increasing delay, followed by a complete stall where no new images seem to
+ * appear.
+ * </p>
+ *
+ * <p>
+ * This operation will fail by throwing an {@link IllegalStateException} if
+ * {@code maxImages} have been acquired with {@link #acquireNextImage} or
+ * {@link #acquireLatestImage}. In particular a sequence of {@link #acquireNextImage} or
+ * {@link #acquireLatestImage} calls greater than {@link #getMaxImages maxImages} without
+ * calling {@link Image#close} in-between will exhaust the underlying queue. At such a time,
+ * {@link IllegalStateException} will be thrown until more images are released with
+ * {@link Image#close}.
+ * </p>
+ *
+ * @return a new frame of image data, or {@code null} if no image data is available.
+ * @throws IllegalStateException if {@code maxImages} images are currently acquired
+ * @see #acquireLatestImage
+ */
+ public Image acquireNextImage() {
+ SurfaceImage si = new SurfaceImage();
+ int status = acquireNextSurfaceImage(si);
+
+ switch (status) {
+ case ACQUIRE_SUCCESS:
+ return si;
+ case ACQUIRE_NO_BUFS:
+ return null;
+ case ACQUIRE_MAX_IMAGES:
+ throw new IllegalStateException(
+ String.format(
+ "maxImages (%d) has already been acquired, " +
+ "call #close before acquiring more.", mMaxImages));
+ default:
+ throw new AssertionError("Unknown nativeImageSetup return code " + status);
+ }
}
/**
* <p>Return the frame to the ImageReader for reuse.</p>
*/
- public void releaseImage(Image i) {
+ private void releaseImage(Image i) {
if (! (i instanceof SurfaceImage) ) {
throw new IllegalArgumentException(
"This image was not produced by an ImageReader");
@@ -183,13 +368,16 @@
/**
* Register a listener to be invoked when a new image becomes available
* from the ImageReader.
- * @param listener the listener that will be run
- * @param handler The handler on which the listener should be invoked, or null
- * if the listener should be invoked on the calling thread's looper.
*
- * @throws IllegalArgumentException if no handler specified and the calling thread has no looper
+ * @param listener
+ * The listener that will be run.
+ * @param handler
+ * The handler on which the listener should be invoked, or null
+ * if the listener should be invoked on the calling thread's looper.
+ * @throws IllegalArgumentException
+ * If no handler specified and the calling thread has no looper.
*/
- public void setImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
+ public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
mImageListener = listener;
Looper looper;
@@ -206,12 +394,16 @@
/**
* Callback interface for being notified that a new image is available.
+ *
+ * <p>
* The onImageAvailable is called per image basis, that is, callback fires for every new frame
* available from ImageReader.
+ * </p>
*/
public interface OnImageAvailableListener {
/**
* Callback that is called when a new image is available from ImageReader.
+ *
* @param reader the ImageReader the callback is associated with.
* @see ImageReader
* @see Image
@@ -220,12 +412,17 @@
}
/**
- * Free up all the resources associated with this ImageReader. After
- * Calling this method, this ImageReader can not be used. calling
- * any methods on this ImageReader and Images previously provided by {@link #getNextImage}
- * will result in an IllegalStateException, and attempting to read from
- * ByteBuffers returned by an earlier {@code Plane#getBuffer} call will
+ * Free up all the resources associated with this ImageReader.
+ *
+ * <p>
+ * After calling this method, this ImageReader can not be used. Calling
+ * any methods on this ImageReader and Images previously provided by
+ * {@link #acquireNextImage} or {@link #acquireLatestImage}
+ * will result in an {@link IllegalStateException}, and attempting to read from
+ * {@link ByteBuffer ByteBuffers} returned by an earlier
+ * {@link Image.Plane#getBuffer Plane#getBuffer} call will
* have undefined behavior.
+ * </p>
*/
@Override
public void close() {
@@ -242,11 +439,14 @@
}
/**
- * Only a subset of the formats defined in {@link android.graphics.ImageFormat} and
- * {@link android.graphics.PixelFormat} are supported by ImageReader. When reading RGB
- * data from a surface, the formats defined in {@link android.graphics.PixelFormat}
- * can be used, when reading YUV, JPEG or raw sensor data ( for example, from camera
- * or video decoder), formats from {@link android.graphics.ImageFormat} are used.
+ * Only a subset of the formats defined in
+ * {@link android.graphics.ImageFormat ImageFormat} and
+ * {@link android.graphics.PixelFormat PixelFormat} are supported by
+ * ImageReader. When reading RGB data from a surface, the formats defined in
+ * {@link android.graphics.PixelFormat PixelFormat} can be used, when
+ * reading YUV, JPEG or raw sensor data (for example, from camera or video
+ * decoder), formats from {@link android.graphics.ImageFormat ImageFormat}
+ * are used.
*/
private int getNumPlanesFromFormat() {
switch (mFormat) {
@@ -308,7 +508,7 @@
*/
private long mNativeContext;
- private class SurfaceImage implements android.media.Image {
+ private class SurfaceImage extends android.media.Image {
public SurfaceImage() {
mIsImageValid = false;
}
@@ -404,7 +604,7 @@
mPlanes[i] = nativeCreatePlane(i);
}
}
- private class SurfacePlane implements android.media.Image.Plane {
+ private class SurfacePlane extends android.media.Image.Plane {
// SurfacePlane instance is created by native code when a new SurfaceImage is created
private SurfacePlane(int index, int rowStride, int pixelStride) {
mIndex = index;
@@ -479,9 +679,17 @@
private synchronized native void nativeClose();
private synchronized native void nativeReleaseImage(Image i);
private synchronized native Surface nativeGetSurface();
- private synchronized native boolean nativeImageSetup(Image i);
- /*
+ /**
+ * @return A return code {@code ACQUIRE_*}
+ *
+ * @see #ACQUIRE_SUCCESS
+ * @see #ACQUIRE_NO_BUFS
+ * @see #ACQUIRE_MAX_IMAGES
+ */
+ private synchronized native int nativeImageSetup(Image i);
+
+ /**
* We use a class initializer to allow the native code to cache some
* field offsets.
*/
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 52c0c2d..12f7bd9 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -120,6 +120,14 @@
.fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b");
/**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * UUID for Loudness Enhancer
+ */
+ public static final UUID EFFECT_TYPE_LOUDNESS_ENHANCER = UUID
+ .fromString("fe3199be-aed0-413f-87bb-11260eb63cf1");
+
+ /**
* Null effect UUID. Used when the UUID for effect type of
* @hide
*/
diff --git a/media/java/android/media/audiofx/LoudnessEnhancer.java b/media/java/android/media/audiofx/LoudnessEnhancer.java
new file mode 100644
index 0000000..eb2fb75
--- /dev/null
+++ b/media/java/android/media/audiofx/LoudnessEnhancer.java
@@ -0,0 +1,291 @@
+/*
+ * 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 android.media.audiofx;
+
+import android.media.AudioTrack;
+import android.media.MediaPlayer;
+import android.media.audiofx.AudioEffect;
+import android.util.Log;
+
+import java.util.StringTokenizer;
+
+
+/**
+ * LoudnessEnhancer is an audio effect for increasing audio loudness.
+ * The processing is parametrized by a target gain value, which determines the maximum amount
+ * by which an audio signal will be amplified; signals amplified outside of the sample
+ * range supported by the platform are compressed.
+ * An application creates a LoudnessEnhancer object to instantiate and control a
+ * this audio effect in the audio framework.
+ * To attach the LoudnessEnhancer to a particular AudioTrack or MediaPlayer,
+ * specify the audio session ID of this AudioTrack or MediaPlayer when constructing the effect
+ * (see {@link AudioTrack#getAudioSessionId()} and {@link MediaPlayer#getAudioSessionId()}).
+ */
+
+public class LoudnessEnhancer extends AudioEffect {
+
+ private final static String TAG = "LoudnessEnhancer";
+
+ // These parameter constants must be synchronized with those in
+ // /system/media/audio_effects/include/audio_effects/effect_loudnessenhancer.h
+ /**
+ * The maximum gain applied applied to the signal to process.
+ * It is expressed in millibels (100mB = 1dB) where 0mB corresponds to no amplification.
+ */
+ public static final int PARAM_TARGET_GAIN_MB = 0;
+
+ /**
+ * Registered listener for parameter changes.
+ */
+ private OnParameterChangeListener mParamListener = null;
+
+ /**
+ * Listener used internally to to receive raw parameter change events
+ * from AudioEffect super class
+ */
+ private BaseParameterListener mBaseParamListener = null;
+
+ /**
+ * Lock for access to mParamListener
+ */
+ private final Object mParamListenerLock = new Object();
+
+ /**
+ * @hide
+ * Class constructor.
+ * @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
+ * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+ *
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public LoudnessEnhancer(int audioSession)
+ throws IllegalStateException, IllegalArgumentException,
+ UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_LOUDNESS_ENHANCER, EFFECT_TYPE_NULL, 0, audioSession);
+
+ if (audioSession == 0) {
+ Log.w(TAG, "WARNING: attaching a LoudnessEnhancer to global output mix is deprecated!");
+ }
+ }
+
+ /**
+ * @hide
+ * Class constructor for the LoudnessEnhancer audio effect.
+ * @param priority the priority level requested by the application for controlling the
+ * LoudnessEnhancer engine. As the same engine can be shared by several applications,
+ * this parameter indicates how much the requesting application needs control of effect
+ * parameters. The normal priority is 0, above normal is a positive number, below normal a
+ * negative number.
+ * @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
+ * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+ *
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public LoudnessEnhancer(int priority, int audioSession)
+ throws IllegalStateException, IllegalArgumentException,
+ UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_LOUDNESS_ENHANCER, EFFECT_TYPE_NULL, priority, audioSession);
+
+ if (audioSession == 0) {
+ Log.w(TAG, "WARNING: attaching a LoudnessEnhancer to global output mix is deprecated!");
+ }
+ }
+
+ /**
+ * Set the target gain for the audio effect.
+ * The target gain is the maximum value by which a sample value will be amplified when the
+ * effect is enabled.
+ * @param gainmB the effect target gain expressed in mB. 0mB corresponds to no amplification.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setTargetGain(int gainmB)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_TARGET_GAIN_MB, gainmB));
+ }
+
+ /**
+ * Return the target gain.
+ * @return the effect target gain expressed in mB.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public float getTargetGain()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] value = new int[1];
+ checkStatus(getParameter(PARAM_TARGET_GAIN_MB, value));
+ return value[0];
+ }
+
+ /**
+ * @hide
+ * The OnParameterChangeListener interface defines a method called by the LoudnessEnhancer
+ * when a parameter value has changed.
+ */
+ public interface OnParameterChangeListener {
+ /**
+ * Method called when a parameter value has changed. The method is called only if the
+ * parameter was changed by another application having the control of the same
+ * LoudnessEnhancer engine.
+ * @param effect the LoudnessEnhancer on which the interface is registered.
+ * @param param ID of the modified parameter. See {@link #PARAM_GENERIC_PARAM1} ...
+ * @param value the new parameter value.
+ */
+ void onParameterChange(LoudnessEnhancer effect, int param, int value);
+ }
+
+ /**
+ * Listener used internally to receive unformatted parameter change events from AudioEffect
+ * super class.
+ */
+ private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+ private BaseParameterListener() {
+
+ }
+ public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+ // only notify when the parameter was successfully change
+ if (status != AudioEffect.SUCCESS) {
+ return;
+ }
+ OnParameterChangeListener l = null;
+ synchronized (mParamListenerLock) {
+ if (mParamListener != null) {
+ l = mParamListener;
+ }
+ }
+ if (l != null) {
+ int p = -1;
+ int v = Integer.MIN_VALUE;
+
+ if (param.length == 4) {
+ p = byteArrayToInt(param, 0);
+ }
+ if (value.length == 4) {
+ v = byteArrayToInt(value, 0);
+ }
+ if (p != -1 && v != Integer.MIN_VALUE) {
+ l.onParameterChange(LoudnessEnhancer.this, p, v);
+ }
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Registers an OnParameterChangeListener interface.
+ * @param listener OnParameterChangeListener interface registered
+ */
+ public void setParameterListener(OnParameterChangeListener listener) {
+ synchronized (mParamListenerLock) {
+ if (mParamListener == null) {
+ mBaseParamListener = new BaseParameterListener();
+ super.setParameterListener(mBaseParamListener);
+ }
+ mParamListener = listener;
+ }
+ }
+
+ /**
+ * @hide
+ * The Settings class regroups the LoudnessEnhancer parameters. It is used in
+ * conjunction with the getProperties() and setProperties() methods to backup and restore
+ * all parameters in a single call.
+ */
+ public static class Settings {
+ public int targetGainmB;
+
+ public Settings() {
+ }
+
+ /**
+ * Settings class constructor from a key=value; pairs formatted string. The string is
+ * typically returned by Settings.toString() method.
+ * @throws IllegalArgumentException if the string is not correctly formatted.
+ */
+ public Settings(String settings) {
+ StringTokenizer st = new StringTokenizer(settings, "=;");
+ //int tokens = st.countTokens();
+ if (st.countTokens() != 3) {
+ throw new IllegalArgumentException("settings: " + settings);
+ }
+ String key = st.nextToken();
+ if (!key.equals("LoudnessEnhancer")) {
+ throw new IllegalArgumentException(
+ "invalid settings for LoudnessEnhancer: " + key);
+ }
+ try {
+ key = st.nextToken();
+ if (!key.equals("targetGainmB")) {
+ throw new IllegalArgumentException("invalid key name: " + key);
+ }
+ targetGainmB = Integer.parseInt(st.nextToken());
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("invalid value for key: " + key);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String str = new String (
+ "LoudnessEnhancer"+
+ ";targetGainmB="+Integer.toString(targetGainmB)
+ );
+ return str;
+ }
+ };
+
+
+ /**
+ * @hide
+ * Gets the LoudnessEnhancer properties. This method is useful when a snapshot of current
+ * effect settings must be saved by the application.
+ * @return a LoudnessEnhancer.Settings object containing all current parameters values
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public LoudnessEnhancer.Settings getProperties()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ Settings settings = new Settings();
+ int[] value = new int[1];
+ checkStatus(getParameter(PARAM_TARGET_GAIN_MB, value));
+ settings.targetGainmB = value[0];
+ return settings;
+ }
+
+ /**
+ * @hide
+ * Sets the LoudnessEnhancer properties. This method is useful when bass boost settings
+ * have to be applied from a previous backup.
+ * @param settings a LoudnessEnhancer.Settings object containing the properties to apply
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setProperties(LoudnessEnhancer.Settings settings)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_TARGET_GAIN_MB, settings.targetGainmB));
+ }
+}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 94f20bc..a03dbf3 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -43,13 +43,16 @@
using namespace android;
-static const char* const OutOfResourcesException =
- "android/view/Surface$OutOfResourcesException";
-
enum {
IMAGE_READER_MAX_NUM_PLANES = 3,
};
+enum {
+ ACQUIRE_SUCCESS = 0,
+ ACQUIRE_NO_BUFFERS = 1,
+ ACQUIRE_MAX_IMAGES = 2,
+};
+
static struct {
jfieldID mNativeContext;
jmethodID postEventFromNative;
@@ -685,14 +688,14 @@
ctx->returnLockedBuffer(buffer);
}
-static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
+static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz,
jobject image)
{
ALOGV("%s:", __FUNCTION__);
JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
if (ctx == NULL) {
jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
- return false;
+ return -1;
}
CpuConsumer* consumer = ctx->getCpuConsumer();
@@ -700,27 +703,22 @@
if (buffer == NULL) {
ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
" maxImages buffers");
- jniThrowException(env, OutOfResourcesException,
- "Too many outstanding images, close existing images"
- " to be able to acquire more.");
- return false;
+ return ACQUIRE_MAX_IMAGES;
}
status_t res = consumer->lockNextBuffer(buffer);
if (res != NO_ERROR) {
if (res != BAD_VALUE /*no buffers*/) {
if (res == NOT_ENOUGH_DATA) {
- jniThrowException(env, OutOfResourcesException,
- "Too many outstanding images, close existing images"
- " to be able to acquire more.");
+ return ACQUIRE_MAX_IMAGES;
} else {
ALOGE("%s Fail to lockNextBuffer with error: %d ",
__FUNCTION__, res);
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ jniThrowExceptionFmt(env, "java/lang/AssertionError",
"Unknown error (%d) when we tried to lock buffer.",
res);
}
}
- return false;
+ return ACQUIRE_NO_BUFFERS;
}
// Check if the left-top corner of the crop rect is origin, we currently assume this point is
@@ -730,7 +728,7 @@
ALOGE("crop left: %d, top = %d", lt.x, lt.y);
jniThrowException(env, "java/lang/UnsupportedOperationException",
"crop left top corner need to at origin");
- return false;
+ return -1;
}
// Check if the producer buffer configurations match what ImageReader configured.
@@ -739,11 +737,9 @@
int outputHeight = buffer->height;
// Correct width/height when crop is set.
- if (buffer->crop.getWidth() > 0) {
- outputWidth = buffer->crop.getWidth() + 1;
- }
- if (buffer->crop.getHeight() > 0) {
- outputHeight = buffer->crop.getHeight() + 1;
+ if (!buffer->crop.isEmpty()) {
+ outputWidth = buffer->crop.getWidth();
+ outputHeight = buffer->crop.getHeight();
}
int imageReaderWidth = ctx->getBufferWidth();
@@ -761,6 +757,7 @@
jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
"Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
+ return -1;
}
if (ctx->getBufferFormat() != buffer->format) {
@@ -777,14 +774,14 @@
buffer->format, ctx->getBufferFormat());
jniThrowException(env, "java/lang/UnsupportedOperationException",
msg.string());
- return false;
+ return -1;
}
// Set SurfaceImage instance member variables
Image_setBuffer(env, image, buffer);
env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
static_cast<jlong>(buffer->timestamp));
- return true;
+ return ACQUIRE_SUCCESS;
}
static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
@@ -855,7 +852,7 @@
{"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init },
{"nativeClose", "()V", (void*)ImageReader_close },
{"nativeReleaseImage", "(Landroid/media/Image;)V", (void*)ImageReader_imageRelease },
- {"nativeImageSetup", "(Landroid/media/Image;)Z", (void*)ImageReader_imageSetup },
+ {"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup },
{"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface },
};
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index ecdc287..64b12b7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -49,6 +49,7 @@
addMediaPlayerStateUnitTests(suite);
addMediaScannerUnitTests(suite);
addCameraUnitTests(suite);
+ addImageReaderTests(suite);
return suite;
}
@@ -65,6 +66,10 @@
suite.addTestSuite(CameraMetadataTest.class);
}
+ private void addImageReaderTests(TestSuite suite) {
+ suite.addTestSuite(ImageReaderTest.class);
+ }
+
// Running all unit tests checking the state machine may be time-consuming.
private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) {
suite.addTestSuite(MediaMetadataRetrieverTest.class);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 2d26ac7..7b2a20e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -61,6 +61,7 @@
private SurfaceHolder mSurfaceHolder = null;
private static final int NUM_STRESS_LOOP = 10;
private static final int NUM_PLAYBACk_IN_EACH_LOOP = 20;
+ private static final int SHORT_WAIT = 2 * 1000; // 2 seconds
private static final long MEDIA_STRESS_WAIT_TIME = 5000; //5 seconds
private static final String MEDIA_MEMORY_OUTPUT =
"/sdcard/mediaMemOutput.txt";
@@ -99,16 +100,17 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+ //Insert a 2 second before launching the test activity. This is
+ //the workaround for the race condition of requesting the updated surface.
+ Thread.sleep(SHORT_WAIT);
+ getActivity();
//Check if the device support the camcorder
- CamcorderProfile mCamcorderProfile = CamcorderProfile.get(CAMERA_ID);
+ mCamcorderProfile = CamcorderProfile.get(CAMERA_ID);
if (mCamcorderProfile != null) {
mVideoWidth = mCamcorderProfile.videoFrameWidth;
mVideoHeight = mCamcorderProfile.videoFrameHeight;
+ Log.v(TAG, "height = " + mVideoHeight + " width= " + mVideoWidth);
}
- //Insert a 2 second before launching the test activity. This is
- //the workaround for the race condition of requesting the updated surface.
- Thread.sleep(2000);
- getActivity();
if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump)
MediaTestUtil.getNativeHeapDump(this.getName() + "_before");
@@ -246,6 +248,8 @@
Thread.sleep(MEDIA_STRESS_WAIT_TIME);
mRecorder.stop();
mRecorder.release();
+ //Insert 2 seconds to make sure the camera released.
+ Thread.sleep(SHORT_WAIT);
} catch (Exception e) {
Log.v("record video failed ", e.toString());
mRecorder.release();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
new file mode 100644
index 0000000..f6cd990
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import static org.mockito.Mockito.*;
+
+import android.graphics.ImageFormat;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageReader;
+import android.media.ImageReader.OnImageAvailableListener;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ImageReaderTest extends AndroidTestCase {
+
+ private static final String TAG = "ImageReaderTest-unit";
+
+ private static final int DEFAULT_WIDTH = 640;
+ private static final int DEFAULT_HEIGHT = 480;
+ private static final int DEFAULT_FORMAT = ImageFormat.YUV_420_888;
+ private static final int DEFAULT_MAX_IMAGES = 3;
+
+ private ImageReader mReader;
+ private Image mImage1;
+ private Image mImage2;
+ private Image mImage3;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ /**
+ * Workaround for mockito and JB-MR2 incompatibility
+ *
+ * Avoid java.lang.IllegalArgumentException: dexcache == null
+ * https://code.google.com/p/dexmaker/issues/detail?id=2
+ */
+ System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
+
+ // TODO: refactor above into one of the test runners
+
+ mReader = spy(ImageReader.newInstance(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ DEFAULT_MAX_IMAGES));
+ mImage1 = mock(Image.class);
+ mImage2 = mock(Image.class);
+ mImage3 = mock(Image.class);
+
+ /**
+ * Ensure rest of classes are mockable
+ */
+ {
+ mock(Plane.class);
+ mock(OnImageAvailableListener.class);
+ }
+
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mReader.close();
+
+ super.tearDown();
+ }
+
+ /**
+ * Return null when there is nothing in the image queue.
+ */
+ @SmallTest
+ public void testGetLatestImageEmpty() {
+ when(mReader.acquireNextImage()).thenReturn(null);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
+ assertEquals(null, mReader.acquireLatestImage());
+ }
+
+ /**
+ * Return the last image from the image queue, close up the rest.
+ */
+ @SmallTest
+ public void testGetLatestImage1() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
+ assertEquals(mImage1, mReader.acquireLatestImage());
+ verify(mImage1, never()).close();
+ }
+
+ /**
+ * Return the last image from the image queue, close up the rest.
+ */
+ @SmallTest
+ public void testGetLatestImage2() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).thenReturn(null);
+ assertEquals(mImage2, mReader.acquireLatestImage());
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, never()).close();
+ }
+
+ /**
+ * Return the last image from the image queue, close up the rest.
+ */
+ @SmallTest
+ public void testGetLatestImage3() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+ thenReturn(mImage3).
+ thenReturn(null);
+ assertEquals(mImage3, mReader.acquireLatestImage());
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, atLeastOnce()).close();
+ verify(mImage3, never()).close();
+ }
+
+ /**
+ * Return null if get a IllegalStateException with no images in the queue.
+ */
+ @SmallTest
+ public void testGetLatestImageTooManyBuffersAcquiredEmpty() {
+ when(mReader.acquireNextImage()).thenThrow(new IllegalStateException());
+ try {
+ mReader.acquireLatestImage();
+ fail("Expected IllegalStateException to be thrown");
+ } catch(IllegalStateException e) {
+ }
+ }
+
+ /**
+ * All images are cleaned up when we get an unexpected Error.
+ */
+ @SmallTest
+ public void testGetLatestImageExceptionalError() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+ thenReturn(mImage3).
+ thenThrow(new OutOfMemoryError());
+ try {
+ mReader.acquireLatestImage();
+ fail("Impossible");
+ } catch(OutOfMemoryError e) {
+ }
+
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, atLeastOnce()).close();
+ verify(mImage3, atLeastOnce()).close();
+ }
+
+ /**
+ * All images are cleaned up when we get an unexpected RuntimeException.
+ */
+ @SmallTest
+ public void testGetLatestImageExceptionalRuntime() {
+
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+ thenReturn(mImage3).
+ thenThrow(new RuntimeException());
+ try {
+ mReader.acquireLatestImage();
+ fail("Impossible");
+ } catch(RuntimeException e) {
+ }
+
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, atLeastOnce()).close();
+ verify(mImage3, atLeastOnce()).close();
+ }
+}
diff --git a/media/tests/SoundPoolTest/AndroidManifest.xml b/media/tests/SoundPoolTest/AndroidManifest.xml
index 126276c..8a29052 100644
--- a/media/tests/SoundPoolTest/AndroidManifest.xml
+++ b/media/tests/SoundPoolTest/AndroidManifest.xml
@@ -8,4 +8,5 @@
</intent-filter>
</activity>
</application>
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8"/>
</manifest>
diff --git a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
index 33db2dd..cc3306c 100644
--- a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
+++ b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
@@ -143,7 +143,7 @@
if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
sleep(50);
}
- if (DEBUG) Log.d(LOG_TAG, "End scale test");
+ if (DEBUG) Log.d(LOG_TAG, "End sounds test");
return true;
}
@@ -165,7 +165,7 @@
if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
sleep(50);
}
- if (DEBUG) Log.d(LOG_TAG, "End sounds test");
+ if (DEBUG) Log.d(LOG_TAG, "End scale test");
return true;
}
@@ -189,6 +189,7 @@
if (DEBUG) Log.d(LOG_TAG, "Change rate " + mScale[step]);
}
mSoundPool.stop(id);
+ if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
if (DEBUG) Log.d(LOG_TAG, "End rate test");
return true;
}
@@ -205,34 +206,38 @@
Log.e(LOG_TAG, "Error occurred starting note");
return false;
}
- sleep(250);
+ sleep(1000);
// play a low priority sound
- int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+ int id = mSoundPool.play(mSounds[1], DEFAULT_VOLUME, DEFAULT_VOLUME,
LOW_PRIORITY, DEFAULT_LOOP, 1.0f);
- if (id > 0) {
+ if (id != 0) {
Log.e(LOG_TAG, "Normal > Low priority test failed");
result = false;
mSoundPool.stop(id);
} else {
- Log.e(LOG_TAG, "Normal > Low priority test passed");
+ sleep(1000);
+ Log.i(LOG_TAG, "Normal > Low priority test passed");
}
- sleep(250);
// play a high priority sound
- id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+ id = mSoundPool.play(mSounds[2], DEFAULT_VOLUME, DEFAULT_VOLUME,
HIGH_PRIORITY, DEFAULT_LOOP, 1.0f);
if (id == 0) {
Log.e(LOG_TAG, "High > Normal priority test failed");
result = false;
} else {
- Log.e(LOG_TAG, "High > Normal priority test passed");
+ sleep(1000);
+ Log.i(LOG_TAG, "Stopping high priority");
+ mSoundPool.stop(id);
+ sleep(1000);
+ Log.i(LOG_TAG, "High > Normal priority test passed");
}
- sleep(250);
- mSoundPool.stop(id);
// stop normal note
+ Log.i(LOG_TAG, "Stopping normal priority");
mSoundPool.stop(normalId);
+ sleep(1000);
if (DEBUG) Log.d(LOG_TAG, "End priority test");
return result;
@@ -250,17 +255,21 @@
Log.e(LOG_TAG, "Error occurred starting note");
return false;
}
- sleep(250);
+ sleep(2500);
// pause and resume sound a few times
for (int count = 0; count < 5; count++) {
+ if (DEBUG) Log.d(LOG_TAG, "Pause note " + id);
mSoundPool.pause(id);
- sleep(250);
+ sleep(1000);
+ if (DEBUG) Log.d(LOG_TAG, "Resume note " + id);
mSoundPool.resume(id);
- sleep(250);
+ sleep(1000);
}
+ if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
mSoundPool.stop(id);
+ sleep(1000);
// play 5 sounds, forces one to be stolen
int ids[] = new int[5];
@@ -272,18 +281,21 @@
Log.e(LOG_TAG, "Error occurred starting note");
return false;
}
- sleep(250);
+ sleep(1000);
}
// pause and resume sound a few times
for (int count = 0; count < 5; count++) {
+ if (DEBUG) Log.d(LOG_TAG, "autoPause");
mSoundPool.autoPause();
- sleep(250);
+ sleep(1000);
+ if (DEBUG) Log.d(LOG_TAG, "autoResume");
mSoundPool.autoResume();
- sleep(250);
+ sleep(1000);
}
for (int i = 0; i < 5; i++) {
+ if (DEBUG) Log.d(LOG_TAG, "Stop note " + ids[i]);
mSoundPool.stop(ids[i]);
}
@@ -302,9 +314,9 @@
return false;
}
- // pan from left to right
+ // pan from right to left
for (int count = 0; count < 101; count++) {
- sleep(20);
+ sleep(50);
double radians = PI_OVER_2 * count / 100.0;
float leftVolume = (float) Math.sin(radians);
float rightVolume = (float) Math.cos(radians);
diff --git a/media/tests/audiotests/Android.mk b/media/tests/audiotests/Android.mk
new file mode 100644
index 0000000..69f0bb5
--- /dev/null
+++ b/media/tests/audiotests/Android.mk
@@ -0,0 +1,21 @@
+ifeq ($(TARGET_ARCH),arm)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= shared_mem_test
+LOCAL_SRC_FILES := \
+ shared_mem_test.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libc \
+ libcutils \
+ libutils \
+ libbinder \
+ libhardware_legacy \
+ libmedia
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/media/tests/audiotests/shared_mem_test.cpp b/media/tests/audiotests/shared_mem_test.cpp
new file mode 100644
index 0000000..992c900
--- /dev/null
+++ b/media/tests/audiotests/shared_mem_test.cpp
@@ -0,0 +1,216 @@
+// 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.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+#define LOG_NDEBUG 0
+#define LOG_TAG "shared_mem_test"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <cutils/properties.h>
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+#include <math.h>
+
+#include "shared_mem_test.h"
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/ProcessState.h>
+
+
+#include <utils/Log.h>
+
+#include <fcntl.h>
+
+namespace android {
+
+/************************************************************
+*
+* Constructor
+*
+************************************************************/
+AudioTrackTest::AudioTrackTest(void) {
+
+ InitSine(); // init sine table
+
+}
+
+
+/************************************************************
+*
+*
+************************************************************/
+void AudioTrackTest::Execute(void) {
+ if (Test01() == 0) {
+ ALOGD("01 passed\n");
+ } else {
+ ALOGD("01 failed\n");
+ }
+}
+
+/************************************************************
+*
+* Shared memory test
+*
+************************************************************/
+#define BUF_SZ 44100
+
+int AudioTrackTest::Test01() {
+
+ sp<MemoryDealer> heap;
+ sp<IMemory> iMem;
+ uint8_t* p;
+
+ short smpBuf[BUF_SZ];
+ long rate = 44100;
+ unsigned long phi;
+ unsigned long dPhi;
+ long amplitude;
+ long freq = 1237;
+ float f0;
+
+ f0 = pow(2., 32.) * freq / (float)rate;
+ dPhi = (unsigned long)f0;
+ amplitude = 1000;
+ phi = 0;
+ Generate(smpBuf, BUF_SZ, amplitude, phi, dPhi); // fill buffer
+
+ for (int i = 0; i < 1024; i++) {
+ heap = new MemoryDealer(1024*1024, "AudioTrack Heap Base");
+
+ iMem = heap->allocate(BUF_SZ*sizeof(short));
+
+ p = static_cast<uint8_t*>(iMem->pointer());
+ memcpy(p, smpBuf, BUF_SZ*sizeof(short));
+
+ sp<AudioTrack> track = new AudioTrack(AUDIO_STREAM_MUSIC,// stream type
+ rate,
+ AUDIO_FORMAT_PCM_16_BIT,// word length, PCM
+ AUDIO_CHANNEL_OUT_MONO,
+ iMem);
+
+ status_t status = track->initCheck();
+ if(status != NO_ERROR) {
+ track.clear();
+ ALOGD("Failed for initCheck()");
+ return -1;
+ }
+
+ // start play
+ ALOGD("start");
+ track->start();
+
+ usleep(20000);
+
+ ALOGD("stop");
+ track->stop();
+ iMem.clear();
+ heap.clear();
+ usleep(20000);
+ }
+
+ return 0;
+
+}
+
+/************************************************************
+*
+* Generate a mono buffer
+* Error is less than 3lsb
+*
+************************************************************/
+void AudioTrackTest::Generate(short *buffer, long bufferSz, long amplitude, unsigned long &phi, long dPhi)
+{
+ long pi13 = 25736; // 2^13*pi
+ // fill buffer
+ for(int i0=0; i0<bufferSz; i0++) {
+ long sample;
+ long l0, l1;
+
+ buffer[i0] = ComputeSine( amplitude, phi);
+ phi += dPhi;
+ }
+}
+
+/************************************************************
+*
+* Generate a sine
+* Error is less than 3lsb
+*
+************************************************************/
+short AudioTrackTest::ComputeSine(long amplitude, long phi)
+{
+ long pi13 = 25736; // 2^13*pi
+ long sample;
+ long l0, l1;
+
+ sample = (amplitude*sin1024[(phi>>22) & 0x3ff]) >> 15;
+ // correct with interpolation
+ l0 = (phi>>12) & 0x3ff; // 2^20 * x / (2*pi)
+ l1 = (amplitude*sin1024[((phi>>22) + 256) & 0x3ff]) >> 15; // 2^15*cosine
+ l0 = (l0 * l1) >> 10;
+ l0 = (l0 * pi13) >> 22;
+ sample = sample + l0;
+
+ return (short)sample;
+}
+
+
+/************************************************************
+*
+* init sine table
+*
+************************************************************/
+void AudioTrackTest::InitSine(void) {
+ double phi = 0;
+ double dPhi = 2 * M_PI / SIN_SZ;
+ for(int i0 = 0; i0<SIN_SZ; i0++) {
+ long d0;
+
+ d0 = 32768. * sin(phi);
+ phi += dPhi;
+ if(d0 >= 32767) d0 = 32767;
+ if(d0 <= -32768) d0 = -32768;
+ sin1024[i0] = (short)d0;
+ }
+}
+
+/************************************************************
+*
+* main in name space
+*
+************************************************************/
+int main() {
+ ProcessState::self()->startThreadPool();
+ AudioTrackTest *test;
+
+ test = new AudioTrackTest();
+ test->Execute();
+ delete test;
+
+ return 0;
+}
+
+}
+
+/************************************************************
+*
+* global main
+*
+************************************************************/
+int main(int argc, char *argv[]) {
+
+ return android::main();
+}
diff --git a/media/tests/audiotests/shared_mem_test.h b/media/tests/audiotests/shared_mem_test.h
new file mode 100644
index 0000000..f495955
--- /dev/null
+++ b/media/tests/audiotests/shared_mem_test.h
@@ -0,0 +1,27 @@
+// Copyright 2008 The Android Open Source Project
+
+#ifndef AUDIOTRACKTEST_H_
+#define AUDIOTRACKTEST_H_
+
+namespace android {
+
+class AudioTrackTest{
+ public:
+ AudioTrackTest(void);
+ ~AudioTrackTest() {};
+
+ void Execute(void);
+ int Test01();
+
+ void Generate(short *buffer, long bufferSz, long amplitude, unsigned long &phi, long dPhi);
+ void InitSine();
+ short ComputeSine(long amplitude, long phi);
+
+ #define SIN_SZ 1024
+ short sin1024[SIN_SZ]; // sine table 2*pi = 1024
+};
+
+};
+
+
+#endif /*AUDIOTRACKTEST_H_*/
diff --git a/packages/BackupRestoreConfirmation/res/values-en-rIN/strings.xml b/packages/BackupRestoreConfirmation/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..d096d98
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-en-rIN/strings.xml
@@ -0,0 +1,38 @@
+<?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">"Full backup"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Full restoration"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"A full backup of all data to a connected desktop computer has been requested. Do you want to allow this to happen?\n\nIf you did not request the backup yourself, do not allow the operation to proceed."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Back up my data"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Do not back up"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"A full restore of all data from a connected desktop computer has been requested. Do you want to allow this to happen?\n\nIf you did not request the restore yourself, do not allow the operation to proceed. This will replace any data currently on the device!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Restore my data"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Do not restore"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Please enter your current backup password below:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Please enter your device encryption password below."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Please enter your device encryption password below. This will also be used to encrypt the backup archive."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Please enter a password to use for encrypting the full backup data. If this is left blank, your current backup password will be used:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"If you wish to encrypt the full backup data, enter a password below:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"If the restore data is encrypted, please enter the password below:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Backup starting..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Backup finished"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Restoration starting..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Restoration ended"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Operation timed out"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-et-rEE/strings.xml b/packages/BackupRestoreConfirmation/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..0f5fde2
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-et-rEE/strings.xml
@@ -0,0 +1,38 @@
+<?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">"Täielik varundus"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Täielik taastamine"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Taotleti kõikide andmete varundamist ühendatud lauaarvutist. Kas soovite seda lubada?\n\nKui te ei taotlenud varundust, siis ärge lubage toimingut jätkata."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Varunda mu andmed"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Ära varunda"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Taotletud on kõikide andmete taastamist ühendatud lauaarvutist. Kas soovite seda lubada?\n\nKui te ei taotlenud taastamist, siis ärge lubage toimingut jätkata. See asendab kõik praegu seadmes olevad andmed."</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Taasta mu andmed"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Ära taasta"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Sisestage allpool praegune varunduse parool:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Sisestage allpool oma seadme krüpteerimise parool."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Sisestage allpool oma seadme krüpteerimise parool. Seda kasutatakse ka varukoopiate arhiivi krüpteerimiseks."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Sisestage parool kõikide varundatud andmete krüpteerimise jaoks. Kui jätate selle tühjaks, siis kasutatakse teie praegust varunduse parooli:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Kui soovite kõik varundusandmed krüpteerida, siis sisestage allpool parool:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Kui taasteandmed on krüpteeritud, siis sisestage allpool parool."</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Algab varundamine ..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Varundamine jõudis lõpule"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Algab taastamine ..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Taastamine jõudis lõpule"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Toiming aegus"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-fr-rCA/strings.xml b/packages/BackupRestoreConfirmation/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..8a70fb5
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-fr-rCA/strings.xml
@@ -0,0 +1,38 @@
+<?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">"Sauvegarde complète"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Restauration complète"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Vous avez demandé une sauvegarde complète de l\'ensemble des données vers un ordinateur de bureau connecté. Voulez-vous l\'autoriser?\n\nSi vous n\'avez pas demandé la sauvegarde vous-même, n\'autorisez pas la poursuite de l\'opération."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Sauvegarder mes données"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Ne pas sauvegarder"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Vous avez demandé une restauration complète de l\'ensemble des données à partir d\'un ordinateur de bureau connecté. Voulez-vous l\'autoriser?\n\nSi vous n\'avez pas demandé vous-même la restauration, n\'autorisez pas sa poursuite. Cette opération remplacera toutes les données actuellement sur l\'appareil!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurer mes données"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Ne pas restaurer"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Veuillez saisir votre mot de passe de sauvegarde actuel ci-dessous :"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Veuillez saisir le mot de passe de chiffrement de l\'appareil ci-dessous."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Veuillez saisir le mot de passe de chiffrement de l\'appareil ci-dessous. Il permettra également de chiffrer les archives de sauvegarde."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Veuillez saisir un mot de passe à utiliser pour chiffrer les données de sauvegarde complète. Si ce champ n\'est pas renseigné, votre mot de passe de sauvegarde actuel sera utilisé :"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Si vous souhaitez chiffrer l\'ensemble des données de sauvegarde, veuillez saisir un mot de passe ci-dessous :"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Si les données de restauration sont chiffrées, veuillez saisir le mot de passe ci-dessous :"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Démarrage de la sauvegarde…"</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Sauvegarde terminée."</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Démarrage de la restauration…"</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Restauration terminée."</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"L\'opération a expiré."</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
index dd0c645..0b29804 100644
--- a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
@@ -16,22 +16,22 @@
<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">"पूर्ण बैकअप"</string>
+ <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="allow_restore_button_label" msgid="3081286752277127827">"मेरा डेटा पुनर्स्थापित करें"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"पुनर्स्थापित न करें"</string>
- <string name="current_password_text" msgid="8268189555578298067">"कृपया नीचे अपना वर्तमान बैकअप पासवर्ड डालें:"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"कृपया नीचे अपना वर्तमान सुरक्षित करने का पासवर्ड डालें:"</string>
<string name="device_encryption_restore_text" msgid="1570864916855208992">"कृपया नीचे अपना उपकरण एन्क्रिप्शन पासवर्ड डालें."</string>
- <string name="device_encryption_backup_text" msgid="5866590762672844664">"कृपया अपना उपकरण एन्क्रिप्शन पासवर्ड नीचे दर्ज करें. बैकअप संग्रहण को एन्क्रिप्ट करने के लिए भी इसका उपयोग किया जाएगा."</string>
- <string name="backup_enc_password_text" msgid="4981585714795233099">"कृपया संपूर्ण बैकअप डेटा को एन्क्रिप्ट करने में उपयोग के लिए पासवर्ड डालें. यदि यह खाली छोड़ दिया जाता है, तो आपके वर्तमान बैकअप पासवर्ड का उपयोग किया जाएगा:"</string>
- <string name="backup_enc_password_optional" msgid="1350137345907579306">"यदि आप संपूर्ण बैकअप डेटा एन्क्रिप्ट करना चाहते हैं, तो नीचे पासवर्ड डालें:"</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"कृपया अपना उपकरण सुरक्षित तरीका पासवर्ड नीचे दर्ज करें. बैकअप संग्रहण को एन्क्रिप्ट करने के लिए भी इसका उपयोग किया जाएगा."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"कृपया संपूर्ण सुरक्षित डेटा को एन्क्रिप्ट करने में उपयोग के लिए पासवर्ड डालें. यदि यह खाली छोड़ दिया जाता है, तो आपके वर्तमान बैकअप पासवर्ड का उपयोग किया जाएगा:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"यदि आप संपूर्ण सुरक्षित डेटा को एन्क्रिप्ट करना चाहते हैं, तो नीचे पासवर्ड डालें:"</string>
<string name="restore_enc_password_text" msgid="6140898525580710823">"यदि पुनर्स्थापित डेटा को एन्क्रिप्ट किया गया है, तो कृपया नीचे पासवर्ड डालें:"</string>
- <string name="toast_backup_started" msgid="550354281452756121">"बैकअप प्रारंभ हो रहा है..."</string>
- <string name="toast_backup_ended" msgid="3818080769548726424">"बैकअप पूर्ण"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"सुरक्षित करना शुरु हो रहा है..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"सुरक्षित करना पूर्ण"</string>
<string name="toast_restore_started" msgid="7881679218971277385">"पुनर्स्थापना प्रारंभ हो रही है..."</string>
<string name="toast_restore_ended" msgid="1764041639199696132">"पुनर्स्थापना समाप्त"</string>
<string name="toast_timeout" msgid="5276598587087626877">"कार्यवाही समयबाह्य हो गई"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-hy-rAM/strings.xml b/packages/BackupRestoreConfirmation/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..4db9080
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-hy-rAM/strings.xml
@@ -0,0 +1,38 @@
+<?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">"Ամբողջական պահուստավորում"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Ամբողջական վերականգնում"</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Եթե վերականգնումը ինքներդ չեք հայցել, թուjլ մի տվեք, որ գործողությունը շարունակվի: Դա կփոխարինի ներկայում հեռախոսի մեջ գտնվող ցանկացած տվյալ:"</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>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Խնդրում ենք մուտքագրել ձեր սարքի կոդավորված գաղտնաբառը ներքևում:"</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Խնդրում ենք մուտքագրել ձեր սարքի կոդավորված գաղտնաբառը ներքևում: Այն նաև կօգտագործվի պահուստային արխիվի կոդավորման համար:"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Խնդրում ենք մուտքագրել գաղտնաբառը` ամբողջական պահուստավորվող տվյալները կոդավորելու համար: Եթե այն դատարկ թողնեք, ապա կօգտագործվի ձեր առկա պահուստավորման գաղտնաբառը`"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Եթե ցանկանում եք կոդավորել ամբողջական պահուստավորված տվյալները, մուտքագրեք գաղտնաբառ ստորև`"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Եթե վերականգնվող տվյալները կոդավորված են, խնդրում ենք մուտքագրել գաղտնաբառը ստորև`"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Պահուստավորումը սկսվում է..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Պահուստավորումն ավարտվեց"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Վերականգնումը մեկնարկեց..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Վերականգնումն ավարտվեց"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Գործողության ժամանակը սպառվեց"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-ka-rGE/strings.xml b/packages/BackupRestoreConfirmation/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..9c6f67e
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-ka-rGE/strings.xml
@@ -0,0 +1,38 @@
+<?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">"სრული სარეზერვო კოპირება"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"სრულად აღდგენა"</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="allow_restore_button_label" msgid="3081286752277127827">"ჩემი მონაცემების აღდგენა"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"არ აღადგინო"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"გთხოვთ, ქვემოთ მიუთითოთ თქვენი ამჟამინდელი სათადარიგო პაროლი:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"გთხოვთ, ქვემოთ მიუთითოთ თქვენი მოწყობილობის დაშიფვრის პაროლი."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"გთხოვთ, ქვემოთ მიუთითოთ თქვენი მოწყობილობის დაშიფვრის პაროლი. ეს ასევე გამოყენებული იქნება სათადარიგო არქივის დაშიფრვისათვის."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"გთხოვთ შეიყვანოთ ყველა სამარქაფო ასლის დაშიფრვის პაროლი. თუ ამ ველს ცარიელს დატოვებთ, გამოყენებული იქნება მიმდინარე პაროლი:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"თუ გსურთ სრული ლოკალური სარეზერვო კოპიის დაშიფრვა, შეიყვანეთ პაროლი ქვემოთ:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"თუ აღსადგენი მონაცემები დაშიფრულია, გთხოვთ, შეიყვანოთ პაროლი ქვემოთ:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"ასლების მომზადება იწყება..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"სარეზერვო კოპირება დასრულებულია"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"აღდგენა იწყება..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"აღდგენა დასრულდა"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"ოპერაციის დროის ლიმიტი ამოიწურა"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-km-rKH/strings.xml b/packages/BackupRestoreConfirmation/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..956fdd7
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-km-rKH/strings.xml
@@ -0,0 +1,38 @@
+<?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">"ការបម្រុងទុកពេញលេញ"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"ស្ដារឡើងវិញពេញលេញ"</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="allow_restore_button_label" msgid="3081286752277127827">"ស្ដារទិន្នន័យរបស់ខ្ញុំ"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"កុំស្ដារឡើងវិញ"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"សូមបញ្ចូលពាក្យសម្ងាត់បម្រុងទុកបច្ចុប្បន្នរបស់អ្នកខាងក្រោម៖"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"សូមបញ្ចូលពាក្យសម្ងាត់ដាក់លេខកូដឧបករណ៍របស់អ្នកខាងក្រោម។"</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"សូមបញ្ចូលពាក្យសម្ងាត់ដាក់លេខកូដឧបករណ៍របស់អ្នកខាងក្រោម។ វានឹងត្រូវបានប្រើ ដើម្បីដាក់លេខកូដប័ណ្ណសារបម្រុងទុកផងដែរ។"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"សូមបញ្ចូលពាក្យសម្ងាត់ដើម្បីប្រើសម្រាប់ដាក់លេខកូដទិន្នន័យបម្រុងទុកពេញលេញ។ បើទុកវាទទេ ពាក្យសម្ងាត់បម្រុងទុកបច្ចុប្បន្នរបស់អ្នកនឹងត្រូវបានប្រើ៖"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"បើអ្នកចង់ដាក់លេខកូដទិន្នន័យបម្រុងទុកពេញលេញ បញ្ចូលពាក្យសម្ងាត់ខាងក្រោម៖"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"បើទិន្នន័យស្ដារត្រូវបានដាក់លេខកូដ សូមបញ្ចូលពាក្យសម្ងាត់ខាងក្រោម៖"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"កំពុងចាប់ផ្ដើមបម្រុងទុក..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"ការបម្រុងទុកបានបញ្ចប់"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"ការស្ដារកំពុងចាប់ផ្ដើម..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"ការស្តារបានបញ្ចប់"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"ប្រតិបត្តិការអស់ពេល"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-lo-rLA/strings.xml b/packages/BackupRestoreConfirmation/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..fb28502
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-lo-rLA/strings.xml
@@ -0,0 +1,38 @@
+<?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">"ສຳຮອງຂໍ້ມູນເຕັມຮູບແບບ"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"ກູ້ຂໍ້ມູນເຕັມຮູບແບບ"</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="allow_restore_button_label" msgid="3081286752277127827">"ກູ້ຄືນຂໍ້ມູນຂອງຂ້ອຍ"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"ບໍ່ໃຫ້ກູ້ຄືນ"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"ກະລຸນາປ້ອນລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນທີ່ທ່ານໃຊ້ຢູ່ໃສ່ດ້ານລຸ່ມ:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"ກະລຸນາປ້ອນລະຫັດຜ່ານການເຂົ້າລະຫັດອຸປະກອນຂອງທ່ານໃສ່ດ້ານລຸ່ມ."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"ກະລຸນາປ້ອນລະຫັດຜ່ານການເຂົ້າລະຫັດອຸປະກອນຂອງທ່ານໃສ່ດ້ານລຸ່ມ. ລະຫັດນີ້ຍັງຈະໃຊ້ເພື່ອເຂົ້າລະຫັດຂໍ້ມູນທີ່ສຳຮອງໄວ້."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"ກະລຸນາປ້ອນລະຫັດຜ່ານ ເພື່ອໃຊ້ໃນການເຂົ້າລະຫັດການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບ. ຖ້າປ່ອຍໃຫ້ເປົ່າຫວ່າງໄວ້, ລະຫັດຜ່ານສຳຮອງຂໍ້ມູນທີ່ທ່ານໃຊ້ຢູ່ຈະຖືກນຳໃຊ້ແທນ:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"ຫາກທ່ານຕ້ອງການທີ່ຈະເຂົ້າລະຫັດໃຫ້ກັບການສຳຮອງຂໍ້ມູນທັງໝົດ, ກະລຸນາໃສ່ລະຫັດທາງລຸ່ມນີ້:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"ຫາກຂໍ້ມູນສຳຮອງຖືກເຂົ້າລະຫັດໄວ້, ກະລຸນາໃສ່ລະຫັດຜ່ານທາງດ້ານລຸ່ມນີ້:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"ກຳລັງເລີ່ມການສຳຮອງຂໍ້ມູນ..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"ສຳຮອງຂໍ້ມູນສຳເລັດແລ້ວ"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"ການກູ້ຂໍ້ມູນກຳລັງຈະເລີ່ມ..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"ການກູ້ຂໍ້ມູນສິ້ນສຸດແລ້ວ"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"ໝົດເວລາປະຕິບັດການ"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-mn-rMN/strings.xml b/packages/BackupRestoreConfirmation/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..b2738c0
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-mn-rMN/strings.xml
@@ -0,0 +1,38 @@
+<?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">"Бүрэн нөөшлөх"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Бүрэн сэргээх"</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="allow_restore_button_label" msgid="3081286752277127827">"Миний датаг сэргээх"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Сэргээхгүй"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Одоогийн нөөшлөх нууц үгийг доор оруулна уу:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Төхөөрөмж шифрлэх нууц үгийг доор оруулна уу."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Төхөөрөмж шифрлэх нууц үгийг доор оруулна уу. Энэ нууц үгийг нөөшлөх архивийг шифрлэхэд бас ашиглана."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Бүрэн дата нөөшлөлтийг шифрлэхэд ашиглах нууц үгийг оруулна уу. Хэрэв та хоосон үлдээвэл таны одоогийн нөөшлөлтийн нууц үг ашиглагдах болно:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Хэрэв та бүрэн нөөшлөх датаг шифрлэх бол доор нууц үгийг оруулна уу:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Хэрэв сэргээх дата шифрлэгдсэн бол доор нууц үгийг оруулна уу:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Нөөшлөж эхлэх..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Нөөшлөлт дуусав"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Сэргээлт эхлэж байна..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Сэргээлт дуусав"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Ажиллагааны хугацаа хэтрэв"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-ms-rMY/strings.xml b/packages/BackupRestoreConfirmation/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..65a9ede
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-ms-rMY/strings.xml
@@ -0,0 +1,38 @@
+<?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">"Sandaran penuh"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Pemulihan penuh"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Sandaran lengkap bagi semua data ke komputer meja yang bersambung telah diminta. Adakah anda mahu membenarkan ini berlaku?\n\nJika anda tidak meminta sandaran ini sendiri, jangan benarkan operasi diteruskan."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Sandarkan data saya"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Jangan buat sandaran"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Pemulihan penuh semua data dari komputer meja yang bersambung telah diminta. Adakah anda mahu membenarkan ini berlaku?\n\nJika anda tidak meminta pemulihan ini sendiri, jangan benarkan operasi ini diteruskan. Ini akan menggantikan sebarang data semasa pada peranti!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Pulihkan data saya"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Jangan kembalikan"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Sila masukkan kata laluan sandaran semasa anda di bawah:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Sila masukkan kata laluan penyulitan peranti anda di bawah."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Sila masukkan kata laluan penyulitan peranti anda di bawah. Ini juga akan digunakan untuk menyulitkan arkib sandaran."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Sila masukkan kata laluan yang hendak digunakan untuk menyulitkan data sandaran lengkap. Jika dibiarkan kosong, kata laluan sandaran semasa anda akan digunakan:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Jika anda ingin menyulitkan data sandaran lengkap, masukkan kata laluan di bawah:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Jika pemulihan data disulitkan, sila masukkan kata laluan di bawah:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Sandaran bermula..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Sandaran selesai"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Pemulihan bermula..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Pemulihan berakhir"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Operasi tamat masa"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-zh-rHK/strings.xml b/packages/BackupRestoreConfirmation/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..d3bcd6e
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-zh-rHK/strings.xml
@@ -0,0 +1,38 @@
+<?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">"完整備份"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"完整還原"</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="allow_restore_button_label" msgid="3081286752277127827">"還原我的資料"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"不要還原"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"在下面輸入您目前的備份密碼:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"請在下面輸入您的裝置加密密碼。"</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"請在下面輸入您的裝置加密密碼,這也會用來將封存備份加密。"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"請輸入為完整備份資料加密的專用密碼。如果留空,系統將使用您目前的備份密碼:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"如果您想將完整的備份資料加密,請在下面輸入一組密碼:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"如果還原的資料經過加密處理,請在下面輸入密碼:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"正在開始備份..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"備份完畢"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"正在開始還原..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"還原完畢"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"操作逾時"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-zu/strings.xml b/packages/BackupRestoreConfirmation/res/values-zu/strings.xml
index b62b7af..955b26f 100644
--- a/packages/BackupRestoreConfirmation/res/values-zu/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-zu/strings.xml
@@ -29,7 +29,7 @@
<string name="device_encryption_backup_text" msgid="5866590762672844664">"Uyacelwa ukuba ufake iphasiwedi efakwe kudivayisi yakho ngezansi. lokhu kuzosetshenziswa ukufaka kusilondoloza sokusiza lapho kudingeka."</string>
<string name="backup_enc_password_text" msgid="4981585714795233099">"Sicela ufake iphasiwedi ezosetshenziselwa ukubhala ngokufihlekileyo imininingo eyesekwe ngokulondoloza. Uma lokhu kushiywe kungabhalwe lutho, kuzosetshenziswa iphasiwedi yokweseka ngokulondoloza yamanje:"</string>
<string name="backup_enc_password_optional" msgid="1350137345907579306">"Uma ufuna ukufaka ikhowudi kwimininingo yonke eyesekelwe ngokulondoloza faka i-passowrd engezansi:"</string>
- <string name="restore_enc_password_text" msgid="6140898525580710823">"Uma insiza yokubuyiselwa esimweni kwmininingo ibhalwe ngokufihlekileyo, sicela ufake iphasiwedi engezansi:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Uma uhlelo lokusebenza yokubuyiselwa esimweni kwmininingo ibhalwe ngokufihlekileyo, sicela ufake iphasiwedi engezansi:"</string>
<string name="toast_backup_started" msgid="550354281452756121">"Ukulondoloza kuyaqala..."</string>
<string name="toast_backup_ended" msgid="3818080769548726424">"Ukulondoloza kuphelile"</string>
<string name="toast_restore_started" msgid="7881679218971277385">"Ukubuyisa kuyaqala..."</string>
diff --git a/packages/DefaultContainerService/res/values-en-rIN/strings.xml b/packages/DefaultContainerService/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-en-rIN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-et-rEE/strings.xml b/packages/DefaultContainerService/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-et-rEE/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-fr-rCA/strings.xml b/packages/DefaultContainerService/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..69c4e99
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-fr-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"Aide accès au paquet"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-hy-rAM/strings.xml b/packages/DefaultContainerService/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..1e2f587
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-hy-rAM/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"Փաթեթի մուտքի օժանդակող"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-ka-rGE/strings.xml b/packages/DefaultContainerService/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-ka-rGE/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-km-rKH/strings.xml b/packages/DefaultContainerService/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..1006d56
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-km-rKH/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"កម្មវិធីជំនួយចូលដំណើរការកញ្ចប់"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-lo-rLA/strings.xml b/packages/DefaultContainerService/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-lo-rLA/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-mn-rMN/strings.xml b/packages/DefaultContainerService/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..d9fe647
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-mn-rMN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"Багц хандалтын тусламж"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-ms-rMY/strings.xml b/packages/DefaultContainerService/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..77d7927
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-ms-rMY/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"Pembantu Akses Pakej"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-zh-rHK/strings.xml b/packages/DefaultContainerService/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..9a43509
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-zh-rHK/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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="service_name" msgid="4841491635055379553">"套件存取輔助程式"</string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 2bac95c..2367e4c 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Kon nie dokument stoor nie"</string>
<string name="root_recent" msgid="4470053704320518133">"Onlangs"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> gratis"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Bergingdienste"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Kortpaaie"</string>
<string name="root_type_device" msgid="7121342474653483538">"Toestelle"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Nog programme"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index 70fab08..b940b2e 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"ሰነድ ማስቀመጥ አልተሳካም"</string>
<string name="root_recent" msgid="4470053704320518133">"የቅርብ ጊዜ"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ነፃ"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"የማከማቻ አገልግሎቶች"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"አቋራጮች"</string>
<string name="root_type_device" msgid="7121342474653483538">"መሣሪያዎች"</string>
<string name="root_type_apps" msgid="8838065367985945189">"ተጨማሪ መተግበሪያዎች"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 20a9990..6213450 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"أخفق حفظ المستند"</string>
<string name="root_recent" msgid="4470053704320518133">"الأخيرة"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> خالية"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"خدمات التخزين"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"اختصارات"</string>
<string name="root_type_device" msgid="7121342474653483538">"أجهزة"</string>
<string name="root_type_apps" msgid="8838065367985945189">"المزيد من التطبيقات"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 11bc3ed..6eb4b20 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Запазването на документа не бе успешно"</string>
<string name="root_recent" msgid="4470053704320518133">"Скорошно"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Свободно: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Услуги за съхранение"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Преки пътища"</string>
<string name="root_type_device" msgid="7121342474653483538">"Устройства"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Още приложения"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index d8f0c07..e8d340d 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"No s\'ha pogut desar el document."</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> lliures"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Serveis d\'emmagatzematge"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Dreceres"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositius"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Més aplicacions"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index 2aa9ed4..5d736de 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Uložení dokumentu se nezdařilo"</string>
<string name="root_recent" msgid="4470053704320518133">"Poslední"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Volný prostor: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Služby úložiště"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Klávesové zkratky"</string>
<string name="root_type_device" msgid="7121342474653483538">"Zařízení"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Další aplikace"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 8a10731..0b1026a 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokumentet kunne ikke gemmes"</string>
<string name="root_recent" msgid="4470053704320518133">"Seneste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ledig plads"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Lagringstjenester"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Genveje"</string>
<string name="root_type_device" msgid="7121342474653483538">"Enheder"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Flere apps"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index 9c23c7e..2729764 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokument konnte nicht gespeichert werden."</string>
<string name="root_recent" msgid="4470053704320518133">"Letzte"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> verfügbar"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Speicherdienste"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Verknüpfungen"</string>
<string name="root_type_device" msgid="7121342474653483538">"Geräte"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Weitere Apps"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 879c440..35eabfb 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Αποτυχία αποθήκευσης του εγγράφου"</string>
<string name="root_recent" msgid="4470053704320518133">"Πρόσφατα"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ελεύθερα"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Υπηρεσίες αποθήκευσης"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Συντομεύσεις"</string>
<string name="root_type_device" msgid="7121342474653483538">"Συσκευές"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Περισσότερες εφαρμογές"</string>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 7f06959..15be21d 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Failed to save document"</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> free"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Storage services"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Shortcuts"</string>
<string name="root_type_device" msgid="7121342474653483538">"Devices"</string>
<string name="root_type_apps" msgid="8838065367985945189">"More apps"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 7f06959..15be21d 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Failed to save document"</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> free"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Storage services"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Shortcuts"</string>
<string name="root_type_device" msgid="7121342474653483538">"Devices"</string>
<string name="root_type_apps" msgid="8838065367985945189">"More apps"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 5d42b60..3b4b870 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Error al guardar el documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recientes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> de espacio libre"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Almacenamiento"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Accesos directos"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Más aplicaciones"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 75598d4..3fe73f9 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -24,12 +24,12 @@
<string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string>
<string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string>
<string name="menu_search" msgid="3816712084502856974">"Buscar"</string>
- <string name="menu_settings" msgid="6008033148948428823">"Configuración"</string>
+ <string name="menu_settings" msgid="6008033148948428823">"Ajustes"</string>
<string name="menu_open" msgid="432922957274920903">"Abrir"</string>
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
- <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> seleccionadas"</string>
+ <string name="mode_selected_count" msgid="459111894725594625">"Seleccionado: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
<string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string>
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Error al guardar documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Reciente"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> de espacio libre"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Servicios almacenamiento"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Accesos directos"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Más aplicaciones"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 2544b2d..be76e5d 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokumendi salvestamine ebaõnnestus"</string>
<string name="root_recent" msgid="4470053704320518133">"Hiljutised"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> on vaba"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Mäluruumi teenused"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Otseteed"</string>
<string name="root_type_device" msgid="7121342474653483538">"Seadmed"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Rohkem rakendusi"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 29b9ccf..7dd1bf1 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"ذخیره سند انجام نشد"</string>
<string name="root_recent" msgid="4470053704320518133">"اخیر"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> آزاد"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"خدمات ذخیرهسازی"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"میانبرها"</string>
<string name="root_type_device" msgid="7121342474653483538">"دستگاهها"</string>
<string name="root_type_apps" msgid="8838065367985945189">"برنامههای بیشتر"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index b51a506..c4769c3 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Asiakirjan tallennus epäonnistui"</string>
<string name="root_recent" msgid="4470053704320518133">"Viimeisimmät"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> vapaana"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Tallennuspalvelut"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Pikakuvakkeet"</string>
<string name="root_type_device" msgid="7121342474653483538">"Laitteet"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Lisää sovelluksia"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 8f1646b..3364866 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Échec de l\'enregistrement du document"</string>
<string name="root_recent" msgid="4470053704320518133">"Récents"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> disponible"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Services de stockage"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Raccourcis"</string>
<string name="root_type_device" msgid="7121342474653483538">"Appareils"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Plus d\'applications"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index be7b9a6..a0ae800 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Échec de l\'enregistrement du document."</string>
<string name="root_recent" msgid="4470053704320518133">"Récents"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Espace disponible : <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Services de stockage"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Raccourcis"</string>
<string name="root_type_device" msgid="7121342474653483538">"Appareils"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Autres applications"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 08b3135..5b5ffcb 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"दस्तावेज़ सहेजने में विफल रहा"</string>
<string name="root_recent" msgid="4470053704320518133">"हाल ही के"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> रिक्त"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"संग्रहण सेवाएं"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"शॉर्टकट"</string>
<string name="root_type_device" msgid="7121342474653483538">"उपकरण"</string>
<string name="root_type_apps" msgid="8838065367985945189">"अधिक एप्स"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index e2722ac..8b5e94c 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Nije uspjelo spremanje dokumenta"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedavno"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> besplatno"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Usluge pohrane"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Prečaci"</string>
<string name="root_type_device" msgid="7121342474653483538">"Uređaji"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Više aplikacija"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 9ffd5e9..f1f450a 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Nem sikerült menteni a dokumentumot"</string>
<string name="root_recent" msgid="4470053704320518133">"Legutóbbiak"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> szabad"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Tárhelyszolgáltatások"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Parancsikonok"</string>
<string name="root_type_device" msgid="7121342474653483538">"Eszközök"</string>
<string name="root_type_apps" msgid="8838065367985945189">"További alkalmazások"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index a2698b5..4d21561 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Չհաջողվեց պահել փաստաթուղթը"</string>
<string name="root_recent" msgid="4470053704320518133">"Վերջին"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ազատ է"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Պահուստի ծառայություններ"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Դյուրանցումներ"</string>
<string name="root_type_device" msgid="7121342474653483538">"Սարքեր"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Հավելյալ ծրագրեր"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 83f6b02..695196b 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Gagal menyimpan dokumen"</string>
<string name="root_recent" msgid="4470053704320518133">"Terkini"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> bebas"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Layanan penyimpanan"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Pintasan"</string>
<string name="root_type_device" msgid="7121342474653483538">"Perangkat"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Aplikasi lain"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 5aad049..bb1a1d0 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Impossibile salvare il documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recente"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> liberi"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Servizi di archiviazione"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Scorciatoie"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivi"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Altre app"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 8323b1d..4b99d4d 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"שמירת המסמך נכשלה"</string>
<string name="root_recent" msgid="4470053704320518133">"מהזמן האחרון"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> של שטח פנוי"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"שירותי אחסון"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"קיצורי דרך"</string>
<string name="root_type_device" msgid="7121342474653483538">"מכשירים"</string>
<string name="root_type_apps" msgid="8838065367985945189">"עוד אפליקציות"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 2b4d487..034a14b 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"ドキュメントを保存できませんでした"</string>
<string name="root_recent" msgid="4470053704320518133">"最近"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"空き容量: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"ストレージサービス"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"ショートカット"</string>
<string name="root_type_device" msgid="7121342474653483538">"端末"</string>
<string name="root_type_apps" msgid="8838065367985945189">"その他のアプリ"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index e97202a..89a8fad 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"დოკუმენტის შენახვა ვერ მოხერხდა"</string>
<string name="root_recent" msgid="4470053704320518133">"ბოლო"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> თავისუფალია"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"მეხსიერების სერვისები"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"მალსახმობები"</string>
<string name="root_type_device" msgid="7121342474653483538">"მოწყობილობები"</string>
<string name="root_type_apps" msgid="8838065367985945189">"მეტი აპები"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 63b6a27..876f8055 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"បានបរាជ័យក្នុងការរក្សាទុកឯកសារ"</string>
<string name="root_recent" msgid="4470053704320518133">"ថ្មីៗ"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"ទំនេរ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"សេវាកម្មផ្ដល់ឧបករណ៍ផ្ទុក"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"ផ្លូវកាត់"</string>
<string name="root_type_device" msgid="7121342474653483538">"ឧបករណ៍"</string>
<string name="root_type_apps" msgid="8838065367985945189">"កម្មវិធីច្រើនទៀត"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 2f578eb..2beecd5 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"문서 저장 실패"</string>
<string name="root_recent" msgid="4470053704320518133">"최근"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> 남음"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"저장용량 서비스"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"바로가기"</string>
<string name="root_type_device" msgid="7121342474653483538">"기기"</string>
<string name="root_type_apps" msgid="8838065367985945189">"앱 더보기"</string>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index ef05df4..08f0724 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"ການບັນທຶກເອກະສານລົ້ມເຫລວ"</string>
<string name="root_recent" msgid="4470053704320518133">"ຫາກໍໃຊ້"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"ຟຣີ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"ບໍລິການບ່ອນຈັດເກັບຂໍ້ມູນ"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"ທາງລັດ"</string>
<string name="root_type_device" msgid="7121342474653483538">"ອຸປະກອນ"</string>
<string name="root_type_apps" msgid="8838065367985945189">"ແອັບຯອື່ນໆ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 799fc19..547d78c 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Nepavyko išsaugoti dokumento"</string>
<string name="root_recent" msgid="4470053704320518133">"Naujausi"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Laisvos vietos: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Saugyklos paslaugos"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Spartieji klavišai"</string>
<string name="root_type_device" msgid="7121342474653483538">"Įrenginiai"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Daugiau programų"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index e9c72d5..7030f7a 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Neizdevās saglabāt dokumentu."</string>
<string name="root_recent" msgid="4470053704320518133">"Pēdējie"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Brīva vieta: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Glabāšanas pakalpojumi"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Saīsnes"</string>
<string name="root_type_device" msgid="7121342474653483538">"Ierīces"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Vairāk lietotņu"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 76d1a20..69d1595 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Документыг хадгалж чадсангүй"</string>
<string name="root_recent" msgid="4470053704320518133">"Саяхны"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> чөлөөтэй"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Сангийн үйлчилгээ"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Товчлол"</string>
<string name="root_type_device" msgid="7121342474653483538">"Төхөөрөмжүүд"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Өөр апп-ууд"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 04ecb1f..ff404c2 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Gagal menyimpan dokumen"</string>
<string name="root_recent" msgid="4470053704320518133">"Terbaharu"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> kosong"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Perkhidmatan storan"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Pintasan"</string>
<string name="root_type_device" msgid="7121342474653483538">"Peranti"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Lebih banyak apl"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 4b42c71..41661c3 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Kunne ikke lagre dokumentet"</string>
<string name="root_recent" msgid="4470053704320518133">"Siste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> gratis"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Lagringstjenester"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Snarveier"</string>
<string name="root_type_device" msgid="7121342474653483538">"Enheter"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Flere apper"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 464a510..4e1dfb7 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Kan document niet opslaan"</string>
<string name="root_recent" msgid="4470053704320518133">"Recent"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> vrij"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Opslagservices"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Sneltoetsen"</string>
<string name="root_type_device" msgid="7121342474653483538">"Apparaten"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Meer apps"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 5d9b28f..412a84b 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -31,15 +31,14 @@
<string name="menu_delete" msgid="8138799623850614177">"Usuń"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Wybrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string>
- <string name="sort_date" msgid="586080032956151448">"Według daty zmiany"</string>
+ <string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string>
<string name="sort_size" msgid="3350681319735474741">"Według rozmiaru"</string>
<string name="drawer_open" msgid="4545466532430226949">"Pokaż elementy główne"</string>
<string name="drawer_close" msgid="7602734368552123318">"Ukryj elementy główne"</string>
<string name="save_error" msgid="6167009778003223664">"Nie udało się zapisać dokumentu"</string>
<string name="root_recent" msgid="4470053704320518133">"Ostatnie"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> wolne"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Usługi pamięci masowej"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Skróty"</string>
<string name="root_type_device" msgid="7121342474653483538">"Urządzenia"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Więcej aplikacji"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index d802e66..42efd0d 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Falha ao guardar o documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> espaço livre"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Serv. de armazenamento"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Atalhos"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Mais aplicações"</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index d4fb0a7..98bd74e 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Falha ao salvar o documento"</string>
<string name="root_recent" msgid="4470053704320518133">"Recentes"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> livres"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Serviços de armazenamento"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Atalhos"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Mais aplicativos"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 3e4a94a..b91d959 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Salvarea documentului nu a reușit"</string>
<string name="root_recent" msgid="4470053704320518133">"Recente"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> spațiu liber"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Servicii de stocare"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Comenzi rapide"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispozitive"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Alte aplicații"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index b2ec07d..b099900 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Не удалось сохранить документ"</string>
<string name="root_recent" msgid="4470053704320518133">"Недавние"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Свободно <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Службы хранения"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Ярлыки"</string>
<string name="root_type_device" msgid="7121342474653483538">"Устройства"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Другие приложения"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 772d595..0275cc6 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokument sa nepodarilo uložiť"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedávne"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Voľné: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Služby úložiska"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Skratky"</string>
<string name="root_type_device" msgid="7121342474653483538">"Zariadenia"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Ďalšie aplikácie"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index d64e504..7e76193 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Dokumenta ni bilo mogoče shraniti"</string>
<string name="root_recent" msgid="4470053704320518133">"Nedavno"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Prosto: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Storitve shrambe"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Bližnjice"</string>
<string name="root_type_device" msgid="7121342474653483538">"Naprave"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Več aplikacij"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index 897e712..48e32e9 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Чување документа није успело"</string>
<string name="root_recent" msgid="4470053704320518133">"Недавно"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"Слободно је <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Услуге складиштења"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Пречице"</string>
<string name="root_type_device" msgid="7121342474653483538">"Уређаји"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Још апликација"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index f398554..7e2a5bb 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Det gick inte att spara dokumentet"</string>
<string name="root_recent" msgid="4470053704320518133">"Senaste"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ledigt"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Lagringstjänster"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Genvägar"</string>
<string name="root_type_device" msgid="7121342474653483538">"Enheter"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Fler appar"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index c911fa4..9730836 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Imeshindwa kuhifadhi hati"</string>
<string name="root_recent" msgid="4470053704320518133">"Hivi karibuni"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> bila malipo"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Huduma za hifadhi"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Njia za mkato"</string>
<string name="root_type_device" msgid="7121342474653483538">"Vifaa"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Programu zaidi"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 1a25f8a..0436f5b 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"การบันทึกเอกสารล้มเหลว"</string>
<string name="root_recent" msgid="4470053704320518133">"ล่าสุด"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"ว่าง <xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"บริการที่เก็บข้อมูล"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"ทางลัด"</string>
<string name="root_type_device" msgid="7121342474653483538">"อุปกรณ์"</string>
<string name="root_type_apps" msgid="8838065367985945189">"แอปเพิ่มเติม"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 20a93cd..298c2e2 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Hindi na-save ang dokumento"</string>
<string name="root_recent" msgid="4470053704320518133">"Kamakailan"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> ang libre"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Mga serbisyo ng storage"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Mga Shortcut"</string>
<string name="root_type_device" msgid="7121342474653483538">"Mga Device"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Higit pang apps"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index f7b0f2c..c3f4594 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Doküman kaydedilemedi"</string>
<string name="root_recent" msgid="4470053704320518133">"En son"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> boş"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Depolama hizmetleri"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Kısayollar"</string>
<string name="root_type_device" msgid="7121342474653483538">"Cihazlar"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Diğer uygulamalar"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 5fa46d8..f49e04c 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Не вдалося зберегти документ"</string>
<string name="root_recent" msgid="4470053704320518133">"Останні"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> вільного місця"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Онлайн-сховища"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Ярлики"</string>
<string name="root_type_device" msgid="7121342474653483538">"Пристрої"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Інші програми"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 4993b9b..2c8a8b1 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Không lưu tài liệu được"</string>
<string name="root_recent" msgid="4470053704320518133">"Gần đây"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> còn trống"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Dịch vụ lưu trữ"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Lối tắt"</string>
<string name="root_type_device" msgid="7121342474653483538">"Thiết bị"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Các ứng dụng khác"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index bff06d4..297312c 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -38,9 +38,8 @@
<string name="save_error" msgid="6167009778003223664">"无法保存文档"</string>
<string name="root_recent" msgid="4470053704320518133">"最近"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"可用空间:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
- <string name="root_type_shortcut" msgid="3318760609471618093">"快捷方式"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"存储服务"</string>
+ <string name="root_type_shortcut" msgid="3318760609471618093">"捷径"</string>
<string name="root_type_device" msgid="7121342474653483538">"设备"</string>
<string name="root_type_apps" msgid="8838065367985945189">"更多应用"</string>
<string name="pref_advanced_devices" msgid="903257239609301276">"显示高级设备"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index a08f6dc..f90f5ff 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"無法儲存文件"</string>
<string name="root_recent" msgid="4470053704320518133">"近期用過"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"可用空間:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"儲存空間服務"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"捷徑"</string>
<string name="root_type_device" msgid="7121342474653483538">"裝置"</string>
<string name="root_type_apps" msgid="8838065367985945189">"更多應用程式"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index d49d789..9ed898a 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"無法儲存文件"</string>
<string name="root_recent" msgid="4470053704320518133">"最近使用過的項目"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"可用空間:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"儲存空間服務"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"捷徑"</string>
<string name="root_type_device" msgid="7121342474653483538">"裝置"</string>
<string name="root_type_apps" msgid="8838065367985945189">"更多應用程式"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index fa3a93e..03ce312 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -38,8 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Yehlulekile ukulondoloza idokhumenti"</string>
<string name="root_recent" msgid="4470053704320518133">"Okwakamuva"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> okhululekile"</string>
- <!-- no translation found for root_type_service (2178854894416775409) -->
- <skip />
+ <string name="root_type_service" msgid="2178854894416775409">"Amasevisi wesitoreji"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Izinqamuleli"</string>
<string name="root_type_device" msgid="7121342474653483538">"Amadivayisi"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Izinhlelo zokusebenza eziningi"</string>
diff --git a/packages/ExternalStorageProvider/res/values-af/strings.xml b/packages/ExternalStorageProvider/res/values-af/strings.xml
index 56552fd..1de881d 100644
--- a/packages/ExternalStorageProvider/res/values-af/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-af/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Eksterne berging"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interne berging"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-am/strings.xml b/packages/ExternalStorageProvider/res/values-am/strings.xml
index f0255a1..e646909 100644
--- a/packages/ExternalStorageProvider/res/values-am/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-am/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ውጫዊ ማከማቻ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ውስጣዊ ማከማቻ"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ar/strings.xml b/packages/ExternalStorageProvider/res/values-ar/strings.xml
index 67a600d..b20a056 100644
--- a/packages/ExternalStorageProvider/res/values-ar/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ar/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"وحدة تخزين خارجية"</string>
<string name="root_internal_storage" msgid="827844243068584127">"وحدة تخزين داخلية"</string>
+ <string name="root_documents" msgid="4051252304075469250">"مستندات"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-bg/strings.xml b/packages/ExternalStorageProvider/res/values-bg/strings.xml
index 919e8b5..f3b4dac 100644
--- a/packages/ExternalStorageProvider/res/values-bg/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-bg/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Външно хранилище"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Вътрешно хранилище"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ca/strings.xml b/packages/ExternalStorageProvider/res/values-ca/strings.xml
index 958ea99..7c0ad8b 100644
--- a/packages/ExternalStorageProvider/res/values-ca/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ca/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Emmagatzematge extern"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Emmagatzematge intern"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-cs/strings.xml b/packages/ExternalStorageProvider/res/values-cs/strings.xml
index 469ecf9..353cb6c 100644
--- a/packages/ExternalStorageProvider/res/values-cs/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-cs/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externí úložiště"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interní úložiště"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-da/strings.xml b/packages/ExternalStorageProvider/res/values-da/strings.xml
index b94e665..a9ecb69 100644
--- a/packages/ExternalStorageProvider/res/values-da/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-da/strings.xml
@@ -16,6 +16,7 @@
<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">"Ekstern lagerplads"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"Intern lagerplads"</string>
+ <string name="app_label" msgid="7123375275748530234">"Ekstern lagring"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenter"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-de/strings.xml b/packages/ExternalStorageProvider/res/values-de/strings.xml
index 1f6ef45..318634a 100644
--- a/packages/ExternalStorageProvider/res/values-de/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-de/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externer Speicher"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interner Speicher"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-el/strings.xml b/packages/ExternalStorageProvider/res/values-el/strings.xml
index 06e26d7..b3aa792 100644
--- a/packages/ExternalStorageProvider/res/values-el/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-el/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Εξωτερικός αποθηκευτικός χώρος"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Εσωτερικός αποθηκευτικός χώρος"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Έγγραφα"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml b/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
index 360d941..f88eb9e 100644
--- a/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rGB/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml b/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
index 360d941..f88eb9e 100644
--- a/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-en-rIN/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml b/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
index 8e35245..7285a34 100644
--- a/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-es-rUS/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Almacenamiento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Almacenamiento interno"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-es/strings.xml b/packages/ExternalStorageProvider/res/values-es/strings.xml
index 8e35245..e7e38b5 100644
--- a/packages/ExternalStorageProvider/res/values-es/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-es/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Almacenamiento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Almacenamiento interno"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml b/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
index d651806..6824e9d 100644
--- a/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Väline talletusruum"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Sisemine salvestusruum"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumendid"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fa/strings.xml b/packages/ExternalStorageProvider/res/values-fa/strings.xml
index 5f82a06..8471fc7 100644
--- a/packages/ExternalStorageProvider/res/values-fa/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fa/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"فضای ذخیره خارجی"</string>
<string name="root_internal_storage" msgid="827844243068584127">"حافظهٔ داخلی"</string>
+ <string name="root_documents" msgid="4051252304075469250">"اسناد"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fi/strings.xml b/packages/ExternalStorageProvider/res/values-fi/strings.xml
index f98b086..9d1fbaa 100644
--- a/packages/ExternalStorageProvider/res/values-fi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fi/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ulkoinen tallennustila"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Sisäinen tallennustila"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentit"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml b/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
index 5861477..294bd69 100644
--- a/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fr-rCA/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Stockage externe"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Mémoire de stockage interne"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-fr/strings.xml b/packages/ExternalStorageProvider/res/values-fr/strings.xml
index 5861477..b3fdd48 100644
--- a/packages/ExternalStorageProvider/res/values-fr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fr/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Stockage externe"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Mémoire de stockage interne"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documents"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hi/strings.xml b/packages/ExternalStorageProvider/res/values-hi/strings.xml
index 302ece1..1227bd4 100644
--- a/packages/ExternalStorageProvider/res/values-hi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hi/strings.xml
@@ -17,5 +17,6 @@
<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">"बाहरी संग्रहण"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"आंतरिक संग्रहण"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"मोबाइल संग्रहण"</string>
+ <string name="root_documents" msgid="4051252304075469250">"दस्तावेज़"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hr/strings.xml b/packages/ExternalStorageProvider/res/values-hr/strings.xml
index 79429a7..a74f8e8 100644
--- a/packages/ExternalStorageProvider/res/values-hr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hr/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Vanjska pohrana"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Unutarnja pohrana"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hu/strings.xml b/packages/ExternalStorageProvider/res/values-hu/strings.xml
index 8175c42..3f72b41 100644
--- a/packages/ExternalStorageProvider/res/values-hu/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hu/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Külső tárhely"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Belső tárhely"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentumok"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml b/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
index c30a03b..5360124 100644
--- a/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hy-rAM/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Արտաքին պահոց"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Ներքին պահոց"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Փաստաթղթեր"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-in/strings.xml b/packages/ExternalStorageProvider/res/values-in/strings.xml
index 7180518..553e656 100644
--- a/packages/ExternalStorageProvider/res/values-in/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-in/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Penyimpanan Eksternal"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Penyimpanan internal"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-it/strings.xml b/packages/ExternalStorageProvider/res/values-it/strings.xml
index c5dcacd..957b5ff 100644
--- a/packages/ExternalStorageProvider/res/values-it/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-it/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Archivio esterno"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Memoria interna"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-iw/strings.xml b/packages/ExternalStorageProvider/res/values-iw/strings.xml
index 62f4471..775506a 100644
--- a/packages/ExternalStorageProvider/res/values-iw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-iw/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"אחסון חיצוני"</string>
<string name="root_internal_storage" msgid="827844243068584127">"אחסון פנימי"</string>
+ <string name="root_documents" msgid="4051252304075469250">"מסמכים"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ja/strings.xml b/packages/ExternalStorageProvider/res/values-ja/strings.xml
index 8d9502562..6c204eb 100644
--- a/packages/ExternalStorageProvider/res/values-ja/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ja/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部ストレージ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"内部ストレージ"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml b/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
index 6a26acd..18920e6 100644
--- a/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ka-rGE/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"გარე მეხსიერება"</string>
<string name="root_internal_storage" msgid="827844243068584127">"შიდა მეხსიერება"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
index 302ce4b..9cf76d4 100644
--- a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ឧបករណ៍ផ្ទុកខាងក្រៅ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ឧបករណ៍ផ្ទុកខាងក្នុង"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ឯកសារ"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ko/strings.xml b/packages/ExternalStorageProvider/res/values-ko/strings.xml
index 07c9e83..4be48bf 100644
--- a/packages/ExternalStorageProvider/res/values-ko/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ko/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"외부 저장소"</string>
<string name="root_internal_storage" msgid="827844243068584127">"내부 저장소"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml b/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
index dd6e55a..cecd9f5 100644
--- a/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lo-rLA/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ບ່ອນຈັດເກັບຂໍ້ມູນພາຍນອກ"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ບ່ອນຈັດເກັບຂໍ້ມູນພາຍໃນ"</string>
+ <string name="root_documents" msgid="4051252304075469250">"ເອກະສານ"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-lt/strings.xml b/packages/ExternalStorageProvider/res/values-lt/strings.xml
index b62efdc..240ea89 100644
--- a/packages/ExternalStorageProvider/res/values-lt/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lt/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Išorinė atmintinė"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Vidinė atmintinė"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumentai"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-lv/strings.xml b/packages/ExternalStorageProvider/res/values-lv/strings.xml
index 23b7a0f..d308fe8 100644
--- a/packages/ExternalStorageProvider/res/values-lv/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lv/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ārējā krātuve"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Iekšējā atmiņa"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml b/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..3d7b7f7
--- /dev/null
+++ b/packages/ExternalStorageProvider/res/values-mn-rMN/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">"Гадаад сан"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Дотоод сан"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документүүд"</string>
+</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml b/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
index 245d52d..e8c6011 100644
--- a/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ms-rMY/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Storan Luaran"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Storan dalaman"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-nb/strings.xml b/packages/ExternalStorageProvider/res/values-nb/strings.xml
index 223eb7a..a9ecb69 100644
--- a/packages/ExternalStorageProvider/res/values-nb/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nb/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Ekstern lagring"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenter"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-nl/strings.xml b/packages/ExternalStorageProvider/res/values-nl/strings.xml
index 402c94b..bde6166 100644
--- a/packages/ExternalStorageProvider/res/values-nl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nl/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externe opslag"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interne opslag"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documenten"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pl/strings.xml b/packages/ExternalStorageProvider/res/values-pl/strings.xml
index 1ac244d..6c5e7d7 100644
--- a/packages/ExternalStorageProvider/res/values-pl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pl/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Pamięć zewnętrzna"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Pamięć wewnętrzna"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
index 629b715..77c89b8 100644
--- a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
@@ -16,6 +16,7 @@
<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">"Armazenamento Externo"</string>
+ <string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-pt/strings.xml b/packages/ExternalStorageProvider/res/values-pt/strings.xml
index bc5b35d..eec824f 100644
--- a/packages/ExternalStorageProvider/res/values-pt/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ro/strings.xml b/packages/ExternalStorageProvider/res/values-ro/strings.xml
index 4295c22..16b963b 100644
--- a/packages/ExternalStorageProvider/res/values-ro/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ro/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Stocare externă"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Stocare internă"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-ru/strings.xml b/packages/ExternalStorageProvider/res/values-ru/strings.xml
index 8c3599d..3dee3b6 100644
--- a/packages/ExternalStorageProvider/res/values-ru/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ru/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Внешний накопитель"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Внутренняя память"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sk/strings.xml b/packages/ExternalStorageProvider/res/values-sk/strings.xml
index 90fc971..73e4552 100644
--- a/packages/ExternalStorageProvider/res/values-sk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sk/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externý ukladací priestor"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Interný ukladací priestor"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sl/strings.xml b/packages/ExternalStorageProvider/res/values-sl/strings.xml
index 7925fec..6ffa698 100644
--- a/packages/ExternalStorageProvider/res/values-sl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sl/strings.xml
@@ -17,5 +17,6 @@
<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">"Zunanja shramba"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"Notranji pomnilnik"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Notranja shramba"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Dokumenti"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sr/strings.xml b/packages/ExternalStorageProvider/res/values-sr/strings.xml
index 23b5561..54238a4 100644
--- a/packages/ExternalStorageProvider/res/values-sr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sr/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Спољна меморија"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Интерна меморија"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sv/strings.xml b/packages/ExternalStorageProvider/res/values-sv/strings.xml
index 6b82ab3..1837096 100644
--- a/packages/ExternalStorageProvider/res/values-sv/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sv/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Extern lagring"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Intern lagring"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-sw/strings.xml b/packages/ExternalStorageProvider/res/values-sw/strings.xml
index 2f9a1f6..0d0e483 100644
--- a/packages/ExternalStorageProvider/res/values-sw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sw/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Hifadhi ya Nje"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Hifadhi ya ndani"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Hati"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-th/strings.xml b/packages/ExternalStorageProvider/res/values-th/strings.xml
index d7e0191..796635e 100644
--- a/packages/ExternalStorageProvider/res/values-th/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-th/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"ที่จัดเก็บข้อมูลภายนอก"</string>
<string name="root_internal_storage" msgid="827844243068584127">"ที่จัดเก็บข้อมูลภายใน"</string>
+ <string name="root_documents" msgid="4051252304075469250">"เอกสาร"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-tl/strings.xml b/packages/ExternalStorageProvider/res/values-tl/strings.xml
index 360d941..529cdc2 100644
--- a/packages/ExternalStorageProvider/res/values-tl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-tl/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"External Storage"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Internal storage"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Mga Dokumento"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-tr/strings.xml b/packages/ExternalStorageProvider/res/values-tr/strings.xml
index 547f4df..ff3f68a 100644
--- a/packages/ExternalStorageProvider/res/values-tr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-tr/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Harici Depolama"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Dahili depolama"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-uk/strings.xml b/packages/ExternalStorageProvider/res/values-uk/strings.xml
index 7a8c161..b8206e0 100644
--- a/packages/ExternalStorageProvider/res/values-uk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-uk/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Зовнішня пам’ять"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Внутрішня пам’ять"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-vi/strings.xml b/packages/ExternalStorageProvider/res/values-vi/strings.xml
index f5c8889..b171c93 100644
--- a/packages/ExternalStorageProvider/res/values-vi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-vi/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Bộ nhớ ngoài"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Bộ nhớ trong"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Tài liệu"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
index 772ef94..0550c50 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rCN/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部存储设备"</string>
<string name="root_internal_storage" msgid="827844243068584127">"内部存储空间"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
index 6163163..62d8afb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部儲存空間"</string>
<string name="root_internal_storage" msgid="827844243068584127">"內部儲存空間"</string>
+ <string name="root_documents" msgid="4051252304075469250">"文件"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
index 6163163..62d8afb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
@@ -18,4 +18,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"外部儲存空間"</string>
<string name="root_internal_storage" msgid="827844243068584127">"內部儲存空間"</string>
+ <string name="root_documents" msgid="4051252304075469250">"文件"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/res/values-zu/strings.xml b/packages/ExternalStorageProvider/res/values-zu/strings.xml
index 3c4cd95..dcaefc5 100644
--- a/packages/ExternalStorageProvider/res/values-zu/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zu/strings.xml
@@ -18,4 +18,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Isitoreji sangaphandle"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Isitoreji sangaphakathi"</string>
+ <!-- no translation found for root_documents (4051252304075469250) -->
+ <skip />
</resources>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..967c3fa
--- /dev/null
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Type PIN code"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Type PUK and new PIN code"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK code"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"New PIN Code"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Touch to type password"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Type password to unlock"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Type PIN to unlock"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Incorrect PIN code."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"To unlock, press Menu, then 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximum Face Unlock attempts exceeded"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Charged"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Charging, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Connect your charger."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Press Menu to unlock."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Network locked"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"No SIM card"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"No SIM card in tablet."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"No SIM card in phone."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Insert a SIM card."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"The SIM card is missing or not readable. Insert a SIM card."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Unusable SIM card."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Your SIM card has been permanently disabled.\n Contact your wireless service provider for another SIM card."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM card is locked."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM card is PUK-locked."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Unlocking SIM card…"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d of %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Add widget"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Empty"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Unlock area expanded."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Unlock area collapsed."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"User selector"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Camera"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Media controls"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widget reordering started."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widget reordering ended."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> deleted."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expand unlock area."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Slide unlock."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Pattern unlock."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face unlock."</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin unlock."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Password unlock."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Pattern area."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Slide area."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Previous track button"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Next track button"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause button"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Play button"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop button"</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="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Done"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Unlock"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Silent"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Sound on"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Search"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Slide down for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Slide left for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Slide right for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Wrong Pattern"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Wrong Password"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Wrong PIN"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Draw your pattern"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Enter SIM PIN"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Enter PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Enter Password"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Enter desired PIN code"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirm desired PIN code"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Unlocking SIM card…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Incorrect PIN code."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Type a PIN that is 4 to 8 numbers."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK code should be 8 numbers or more."</string>
+ <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_login_instructions" msgid="1100551261265506448">"To unlock, sign in with your Google account."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Username (email)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Sign in"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Invalid username or password."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Forgot your username or password?\nVisit "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Checking account…"</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="1575557200627128949">"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 tablet will be reset to factory default and all user data will be lost."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"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 phone will be reset to factory default and all user data will be lost."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The tablet will now be reset to factory default."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The phone will now be reset to factory default."</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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Previous track button"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Next track button"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pause button"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Play button"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stop button"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index d0c79eb..3e4fe54 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -30,7 +30,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se ha superado el número máximo de intentos de desbloqueo facial."</string>
- <string name="keyguard_charged" msgid="3272223906073492454">"Cargado"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Cargada"</string>
<string name="keyguard_plugged_in" msgid="8117572000639998388">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Conecta el cargador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Ve al menú para desbloquear la pantalla."</string>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..0a17a9c
--- /dev/null
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Sisestage PIN-kood"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Sisestage PUK-kood ja uus PIN-kood"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK-kood"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Uus PIN-kood"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Puudutage parooli sisestamiseks"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Avamiseks sisestage parool"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Avamiseks sisestage PIN-kood"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Vale PIN-kood."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Avamiseks vajutage menüüklahvi, seejärel klahvi 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimaalne teenusega Face Unlock avamise katsete arv on ületatud"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Laetud"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Laadimine, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Ühendage laadija."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Avamiseks vajutage menüüklahvi."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Võrk on suletud"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM-kaarti pole"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tahvelarvutis pole SIM-kaarti."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Telefonis pole SIM-kaarti."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Sisestage SIM-kaart."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-kaart puudub või on loetamatu. Sisestage SIM-kaart."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Kasutamiskõlbmatu SIM-kaart."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM-kaart on jäädavalt keelatud.\n Uue SIM-kaardi saamiseks võtke ühendust oma mobiilsideoperaatoriga."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kaart on lukus."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kaart on PUK-lukus."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-kaardi avamine ..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Vidin %2$d/%3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Vidina lisamine."</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tühi"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Avamisala on laiendatud."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Avamisala on ahendatud."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Vidin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kasutaja valija"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Olek"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kaamera"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Meedia juhtnupud"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Vidina ümberkorraldamine algas."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Vidina ümberkorraldamine lõppes."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Vidin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> on kustutatud."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Avamisala laiendamine."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lohistamisega avamine."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Mustriga avamine."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Näoga avamine."</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-koodiga avamine."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Parooliga avamine."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Mustri ala."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Lohistamisala."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Nupp Eelmine lugu"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nupp Järgmine lugu"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Nupp Peata"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Nupp Esita"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Nupp Peata"</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="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Tühista"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Kustuta"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Valmis"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Režiimi muutmine"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Tõstuklahv"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Sisestusklahv"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Luku avamine"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Kaamera"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Hääletu"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Heli on sees"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Otsing"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Lohistage üles: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Lohistage alla: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Lohistage vasakule: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Lohistage paremale: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Hädaabikõne"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unustasin mustri"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Vale muster"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Vale parool"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Vale PIN-kood"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Proovige uuesti <xliff:g id="NUMBER">%d</xliff:g> sekundi pärast."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Joonistage oma muster"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Sisestage SIM-i PIN-kood"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Sisestage PIN-kood"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Sisestage parool"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Üksikasju küsige operaatorilt."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Sisestage soovitud PIN-kood"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Kinnitage soovitud PIN-kood"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kaardi avamine ..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Vale PIN-kood."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Sisestage 4–8-numbriline PIN-kood."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK-koodi pikkus peab olema vähemalt 8 numbrit."</string>
+ <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_login_instructions" msgid="1100551261265506448">"Avamiseks logige sisse oma Google\'i kontoga."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Kasutajanimi (e-post)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Parool"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Logi sisse"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Vale kasutajanimi või parool."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kas unustasite kasutajanime või parooli?\nKülastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Konto kontrollimine ..."</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="1575557200627128949">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse tahvelarvuti tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse telefon tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Olete püüdnud tahvelarvutit <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Tahvelarvuti lähtestatakse nüüd tehase vaikeseadetele."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Olete püüdnud telefoni <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Telefon lähtestatakse nüüd tehase vaikeseadetele."</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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eemalda"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Nupp Eelmine lugu"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Nupp Järgmine lugu"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Nupp Peata"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Nupp Esita"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Nupp Peata"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Teenus puudub."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..35e897d
--- /dev/null
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Saisissez le NIP."</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Saisissez la clé PUK et le nouveau NIP."</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Clé PUK"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Nouveau NIP"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Appuyer pour saisir mot passe"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Saisissez le mot de passe pour déverrouiller le clavier."</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Saisissez le NIP pour déverrouiller le clavier."</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"NIP erroné."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le téléphone, appuyez sur \"Menu\", puis sur 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nombre maximal autorisé de tentatives Face Unlock atteint."</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Chargé"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"En charge (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Branchez votre chargeur."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Appuyez sur \"Menu\" pour déverrouiller l\'appareil."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Réseau verrouillé"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Aucune carte SIM"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Aucune carte SIM n\'est insérée dans la tablette."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Insérez une carte SIM."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Carte SIM absente ou illisible. Veuillez insérer une carte SIM."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Carte SIM inutilisable."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Votre carte SIM a été définitivement désactivée.\n Veuillez contacter votre opérateur de téléphonie mobile pour en obtenir une autre."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La carte SIM est verrouillée."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La carte SIM est verrouillée par clé PUK."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Déverrouillage de la carte SIM en cours…"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d sur %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ajouter un widget"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vide"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Développement de la zone de déverrouillage"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Réduction de la zone de déverrouillage"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Sélecteur d\'utilisateur"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"État"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Caméra"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Commandes multimédias"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Début de la réorganisation des widgets"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Fin de la réorganisation des widgets"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Le widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> a été supprimé."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Développer la zone de déverrouillage"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Déverrouillage en faisant glisser votre doigt sur l\'écran"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Déverrouillage par schéma"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Déverrouillage par reconnaissance faciale"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Déverrouillage par NIP"</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Déverrouillage par mot de passe"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Zone du schéma"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Zone où faire glisser votre doigt sur l\'écran"</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Bouton pour revenir au titre précédent"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Bouton pour atteindre le titre suivant"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Bouton de pause"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Bouton de lecture"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Bouton d\'arrêt"</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="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuler"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Supprimer"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Terminé"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Changement de mode"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Entrée"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Déverrouiller"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Appareil photo"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Mode silencieux"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Son activé"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Recherche"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Faire glisser le doigt vers le haut : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Faire glisser le doigt vers le bas : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Faites glisser votre doigt vers la gauche pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Faites glisser votre doigt vers la droite pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Schéma incorrect."</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Mot de passe incorrect."</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"NIP incorrect."</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Dessinez votre schéma."</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Saisissez le NIP de la carte SIM"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Saisissez le NIP."</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Saisissez votre mot de passe."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Contactez votre opérateur pour en savoir plus."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Saisir le NIP souhaité"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirmer le NIP souhaité"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Déblocage de la carte SIM en cours…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"NIP erroné."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Saisissez un NIP comprenant entre quatre et huit chiffres"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Le code PUK doit contenir au moins 8 chiffres."</string>
+ <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_login_instructions" msgid="1100551261265506448">"Pour déverrouiller l\'appareil, connectez-vous avec votre compte Google."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Nom d\'utilisateur (courriel)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Mot de passe"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Connexion"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'utilisateur ou mot de passe non valide."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe?\nRendez-vous sur la page "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Vérification du compte en cours…"</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="1575557200627128949">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Supprimer"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Bouton pour revenir au titre précédent"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Bouton pour atteindre le titre suivant"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Bouton de pause"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Bouton de lecture"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Bouton d\'arrêt"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index 714d9fb..2c6188a 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -60,11 +60,11 @@
<string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"विजेट <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> को हटा दिया गया."</string>
<string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"अनलॉक क्षेत्र विस्तृत करें."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"स्लाइड अनलॉक."</string>
- <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"प्रतिमान अनलॉक."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"आकार अनलॉक."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"फेस अनलॉक."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"पिन अनलॉक."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"पासवर्ड अनलॉक."</string>
- <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"प्रतिमान क्षेत्र."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"आकार क्षेत्र."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"स्लाइड क्षेत्र."</string>
<string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"पिछला ट्रैक बटन"</string>
<string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"अगला ट्रैक बटन"</string>
@@ -92,12 +92,12 @@
<string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए दाएं स्लाइड करें."</string>
<string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"आपातकालीन कॉल"</string>
- <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"प्रतिमान भूल गए"</string>
- <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत प्रतिमान"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"आकार भूल गए"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत आकार"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"गलत पासवर्ड"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"गलत PIN"</string>
<string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना प्रतिमान आरेखित करें"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना आकार आरेखित करें"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम PIN डालें"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"PIN डालें"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"पासवर्ड डालें"</string>
@@ -110,23 +110,23 @@
<string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK कोड 8 या अधिक संख्या वाला होना चाहिए."</string>
<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_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से साइन इन करें."</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक आकार प्रयास"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से प्रवेश करें."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"उपयोगकर्ता नाम (ईमेल)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
- <string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन करें"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"प्रवेश करें"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"अमान्य उपयोगकर्ता नाम या पासवर्ड."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?\n "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जांच की जा रही है…"</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_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="1575557200627128949">"आप टेबलेट को अनलॉक करने के लिए <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="4051015943038199910">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, फ़ोन फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"आप टेबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. टेबलेट अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"आप फ़ोन को अनलॉक करने के लिए <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">%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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"निकालें"</string>
<string name="keyguard_transport_prev_description" msgid="8229108430245669854">"पिछला ट्रैक बटन"</string>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..19b3c79
--- /dev/null
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Մուտքագրեք PIN կոդը"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Մուտքագրեք PUK-ը և նոր PIN կոդը"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK կոդ"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Նոր PIN ծածկագիր"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Հպեք` գաղտնաբառը մուտքագրելու համար"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Մուտքագրեք գաղտնաբառը ապակողպման համար"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Մուտքագրեք PIN-ը ապակողպման համար"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Սխալ PIN ծածկագիր:"</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Ապակողպման համար սեղմեք Ցանկ, ապա 0:"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Առավելագույն Դեմքով ապակողպման փորձերը գերազանցված են"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Լիցքավորված է"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Լիցքավորում, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Միացրեք ձեր լիցքավորիչը:"</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Ապակողպելու համար սեղմեք Ցանկը:"</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Ցանցը կողպված է"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM քարտ չկա"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Գրասալիկում SIM քարտ չկա:"</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Հեռախոսի մեջ SIM քարտ չկա:"</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Զետեղեք SIM քարտը:"</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM քարտը բացակայում է կամ չի կարող կարդացվել: Մտցրեք SIM քարտ:"</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Անպիտան SIM քարտ:"</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Ձեր SIM քարտը ընդմիշտ կասեցվել է:\nԿապվեք ձեր բջջային ծառայության մատակարարի հետ նոր SIM քարտ ձեռք բերելու համար:"</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM քարտը կողպված է:"</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM քարտը PUK-ով կողպված է:"</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM քարտը ապակողպվում է..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Վիջեթ %2$d of %3$d:"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ավելացնել վիջեթ:"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Դատարկ"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ապակողպման տարածքն ընդլայնված է:"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Ապակողպման տարածքը ետ է ծալված:"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> վիջեթ:"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Օգտվողի ընտրիչ"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Կարգավիճակ"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Ֆոտոխցիկ"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Մեդիա կարգավորումներ"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Վիջեթների վերադասավորումը մեկնարկել է:"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Վիջեթի վերադասավորումն ավարտվեց:"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Վիջեթ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-ը ջնջված է:"</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ընդլայնել ապակողպման տարածությունը:"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Էջի ապակողպում:"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Սխեմայով ապակողպում:"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Դեմքով ապակողպում:"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin-ն ապակողպված է:"</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Գաղտնաբառի ապակողպում:"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Սխեմայի տարածք:"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Սահեցման տարածք:"</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Նախորդ հետագծի կոճակը"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Հաջորդ հետագծի կոճակը"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Դադարի կոճակ"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Նվագարկման կոճակ"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Կանգի կոճակ"</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="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Չեղարկել"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ջնջել"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Կատարված է"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Ռեժիմի փոփոխում"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Մուտք"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Ապակողպել"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Ֆոտոխցիկ"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Լուռ"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Ձայնը միացնել"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Սահեցրեք ցած <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Սահեցրեք ձախ` <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Սահեցրեք աջ` <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
+ <string name="user_switched" msgid="3768006783166984410">"Ներկայիս օգտվողը <xliff:g id="NAME">%1$s</xliff:g>:"</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Արտակարգ իրավիճակի հեռախոսազանգ"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Մոռացել եմ սխեման"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Սխալ սխեմա"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Սխալ գաղտնաբառ"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Սխալ PIN"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Փորձեք կրկին <xliff:g id="NUMBER">%d</xliff:g> վայրկյանից:"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Հավաքեք ձեր սխեման"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Մուտքագրեք SIM-ի PIN-ը"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Մուտքագրեք PIN-ը"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Մուտքագրեք գաղտնաբառը"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM-ը այս պահին անջատված է: Մուտքագրեք PUK կոդը շարունակելու համար: Մանրամասների համար կապվեք օպերատորի հետ:"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Մուտքագրեք ցանկալի PIN ծածկագիրը"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Հաստատեք ցանկալի PIN ծածկագիրը"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ապակողպում է SIM քարտը ..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Սխալ PIN ծածկագիր:"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Մուտքագրեք PIN, որը 4-ից 8 թիվ է:"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK կոդը պետք է լինի 8 կամ ավելի թիվ:"</string>
+ <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_login_instructions" msgid="1100551261265506448">"Ապակողպելու համար` մուտք գործեք ձեր Google հաշվով:"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Օգտանուն (էլփոստ)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Գաղտնաբառը"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Մուտք գործել"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Սխալ օգտանուն կամ գաղտնաբառ:"</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Մոռացե՞լ եք ձեր օգտանունը կամ գաղտնաբառը:\nԱյցելեք "<b>"google.com /accounts/recovery"</b>":"</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Հաշիվը ստուգվում է..."</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="1575557200627128949">"Դուք <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="4051015943038199910">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ փորձ եք արել հեռախոսն ապակողպելու համար: <xliff:g id="NUMBER_1">%d</xliff:g> անգամից ավել անհաջող փորձերից հետո հեռախոսը կվերակարգավորվի գործարանային լռելյայնի, և օգտվողի բոլոր տվյալները կկորեն:"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Դուք <xliff:g id="NUMBER">%d</xliff:g> անգամ սխալ փորձ եք արել գրասալիկն ապակողպելու համար: Գրասալիկն այժմ կվերակարգավորվի գործարանային լռելյայնի:"</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Դուք <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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Հեռացնել"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Նախորդ հետագծի կոճակ"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Հաջորդ հետագծի կոճակ"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Դադարի կոճակ"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Նվագարկման կոճակ"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Դադարի կոճակ"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ծառայություն չկա:"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index 8d36309..c12a0e8 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -29,7 +29,7 @@
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"הקלד קוד PIN לביטול הנעילה"</string>
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"קוד PIN שגוי"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"כדי לבטל את הנעילה, לחץ על \'תפריט\' ולאחר מכן על 0."</string>
- <string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פרצוף"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פנים"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"טעון"</string>
<string name="keyguard_plugged_in" msgid="8117572000639998388">"טוען, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"חבר את המטען."</string>
@@ -61,7 +61,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"הרחב את אזור ביטול הנעילה."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ביטול נעילה באמצעות הסטה."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ביטול נעילה באמצעות ציור קו."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פרצוף."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פנים."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ביטול נעילה באמצעות מספר PIN."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ביטול נעילה באמצעות סיסמה."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"אזור ציור קו."</string>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..b901bf4
--- /dev/null
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"აკრიფეთ PIN კოდი"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"დაბეჭდეთ PUK კოდი და ახალი PIN კოდი."</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK კოდი"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"ახალი PIN კოდი"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384">"შეეხეთ "<font size="17">"-ს პაროლის"</font>" დასაბეჭდად."</string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"განსაბლოკად აკრიფეთ პაროლი"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"განსაბლოკად აკრიფეთ PIN კოდი"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"არასწორი PIN კოდი."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"განბლოკვისათვის დააჭირეთ მენიუს და შემდეგ 0-ს."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"სახის ამოცნობით განბლოკვის მცდელობამ დაშვებულ რაოდენობას გადააჭარბა"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"დამუხტულია"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"მიმდინარეობს დამუხტვა (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"შეაერთეთ დამტენი."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"განბლოკვისთვის დააჭირეთ მენიუს."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"ქსელი ჩაკეტილია"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM ბარათი არ არის"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"ტაბლეტში არ დევს SIM ბარათი."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"არ არის SIM ბარათი ტელეფონში."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"ჩადეთ SIM ბარათი."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM ბარათი არ არის ან არ იკითხება. ჩადეთ SIM ბარათი."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"არამოხმარებადი SIM ბარათი."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"თქვენი SIM ბარათი გამუდმებით გამორთული იყო.\n დაუკავშირდით თქვენი უკაბელო სერვისის პროვაიდერს სხვა SIM ბარათისთვის."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM ბარათი დაბლოკილია."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM ბარათი დაბლოკილია PUK კოდით."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"მიმდინარეობს SIM ბარათის განბლოკვა…"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ვიჯეტი %2$d of %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ვიჯეტის დამატება"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ცარიელი"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"განბლოკვის სივრცე გაშლილია."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"განბლოკვის სივრცე ჩაკეცილია."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ვიჯეტი."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"მომხმარებლის ამომრჩეველი"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"სტატუსი"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"კამერა"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"მედიის მართვის ელემენტები"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"დაიწყო ვიჯეტის ხელახლა განლაგება."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ვიჯეტების გადახარისხება დასრულებულია."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ვიჯეტი <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> წაიშალა."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"განბლოკვის სივრცის გაშლა."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"გასრიალებით განბლოკვა"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"განბლოკვა ნიმუშით."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"განბლოკვა სახით"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"განბლოკვა Pin-ით."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"პაროლის განბლოკვა"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"ნიმუშების სივრცე."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"გადასრიალების სივრცე."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"წინა ჩანაწერის ღილაკი"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"შემდეგი ჩანაწერის ღილაკი"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"პაუზის ღილაკი"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"დაკვრის ღილაკი"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop ღილაკი"</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="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"გაუქმება"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"წაშლა"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"დასრულდა"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"რეჟიმის შეცვლა"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift-"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"შეყვანა"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"განბლოკვა"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"კამერა"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"უხმო"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"ხმის ჩართვა"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"ძიება"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"გაასრიალეთ ზემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"გაასრიალეთ ქვემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"გაასრიალეთ მარცხნივ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"გაასრიალეთ მარჯვნივ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
+ <string name="user_switched" msgid="3768006783166984410">"ამჟამინდელი მომხმარებელი <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"გადაუდებელი დახმარების ზარი"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"დაგავიწყდათ ნიმუში"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"არასწორი ნიმუში"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"არასწორი პაროლი"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"არასწორი PIN"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"კიდევ სცადეთ <xliff:g id="NUMBER">%d</xliff:g> წამში."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"დახატეთ თქვენი ნიმუში."</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN-ის შეყვანა"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"შეიყვანეთ PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"პაროლის შეყვანა"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM ამჟამად დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK კოდი. დეტალებისთვის მიმართეთ მობილურ ოპერატორს."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"სასურველი PIN კოდის შეყვანა"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"სასურველი PIN კოდის დადასტურება"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM ბარათის განბლოკვა…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"არასწორი PIN კოდი."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"აკრიფეთ PIN, რომელიც შედგება 4-დან 8 ციფრამდე."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK კოდი უნდა იყოს რვა ან მეტი ციფრისგან შემდგარი."</string>
+ <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_login_instructions" msgid="1100551261265506448">"განბლოკვისთვის გაიარეთ ავტორიზაცია თქვენი Google ანგარიშით."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"მომხმარებლის სახელი (ელფოსტა)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"პაროლი"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"შესვლა"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"არასწორი სახელი, ან პაროლი."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"დაგავიწყდათ მომხმარებლის სახელი და პაროლი?\nეწვიეთ "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"მიმდინარეობს ანგარიშის შემოწმება…"</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="1575557200627128949">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <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="4051015943038199910">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ ტელეფონზე დაყენდება საწყისი, ქარხნული პარამეტრები და მომხმარებლის ყველა მონაცემი დაიკარგება."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ტაბლეტზე დაყენდება საწყისი, ქარხნული პარამეტრები და მომხმარებლის ყველა მონაცემი დაიკარგება."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"თქვენ <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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ამოშლა"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"წინა ჩანაწერზე გადასვლის ღილაკი"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"შემდეგი ჩანაწერის ღილაკი"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"პაუზის ღილაკი"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"დაკვრის ღილაკი"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"შეჩერების ღილაკი"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"არ არის სერვისი."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..586169e
--- /dev/null
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"បញ្ចូលកូដ PIN"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"បញ្ចូលកូដ PUK និង PIN ថ្មី"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"កូដ PUK"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"កូដ PIN ថ្មី"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"ប៉ះ ដើម្បីបញ្ចូលពាក្យសម្ងាត់"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"បញ្ចូលពាក្យសម្ងាត់ ដើម្បីដោះសោ"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"បញ្ចូលកូដ PIN ដើម្បីដោះសោ"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"កូដ PIN មិនត្រឹមត្រូវ។"</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"ដើម្បីដោះសោ ចុចម៉ឺនុយ បន្ទាប់មក 0 ។"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"បានលើសការព្យាយាមដោះសោតាមទម្រង់មុខ"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"បានបញ្ចូលពេញ"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"បញ្ចូលថ្ម <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"ភ្ជាប់ឧបករណ៍បញ្ចូលថ្ម។"</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"ចុចម៉ឺនុយ ដើម្បីដោះសោ។"</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"បណ្ដាញជាប់សោ"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"គ្មានស៊ីមកាត"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"គ្មានស៊ីមកាតនៅក្នុងកុំព្យូទ័របន្ទះ។"</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"គ្មានស៊ីមកាតក្នុងទូរស័ព្ទ។"</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"បញ្ចូលស៊ីមកាត។"</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"បាត់ស៊ីមកាត ឬមិនអាចអាន។ បញ្ចូលស៊ីមកាត។"</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"ស៊ីមកាតមិនអាចប្រើបាន។"</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"បានបិទស៊ីមកាតរបស់អ្នកជាអចិន្ត្រៃយ៍។\n ទាក់ទងក្រុមហ៊ុនផ្ដល់សេវាកម្មឥតខ្សែសម្រាប់ស៊ីមកាតផ្សេង។"</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ស៊ីមកាតជាប់សោ។"</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ស៊ីមកាតជាប់កូដ PUK ។"</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"កំពុងដោះសោស៊ីមកាត..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ធាតុក្រាហ្វិក %2$d នៃ %3$d ។"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"បន្ថែមធាតុក្រាហ្វិក។"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ទទេ"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"បានពង្រីកផ្ទៃដោះសោ។"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"បានបង្រួមផ្ទៃដោះសោ។"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ធាតុក្រាហ្វិក។"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ឧបករណ៍ជ្រើសអ្នកប្រើ"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"ស្ថានភាព"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ម៉ាស៊ីនថត"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"ពិនិត្យមេឌៀ"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"បានចាប់ផ្ដើមតម្រៀបធាតុក្រាហ្វិកឡើងវិញ។"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"បានបញ្ចប់ការបង្ហាញធាតុក្រាហ្វិក។"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"បានលុបធាតុក្រាហ្វិក <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ។"</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ពង្រីកតំបន់ដោះសោ។"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"រុញដោះសោ។"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"លំនាំដោះសោ។"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ដោះសោតាមទម្រង់មុខ។"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"កូដ PIN ដោះសោ។"</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ពាក្យសម្ងាត់ដោះសោ។"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"ផ្ទៃលំនាំ។"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"ផ្ទៃរុញ។"</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ប៊ូតុងបទមុន"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ប៊ូតុងបទបន្ទាប់"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ប៊ូតុងផ្អាក"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ប៊ូតុងចាក់"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ប៊ូតុងបញ្ឈប់"</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="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះបង់"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"លុប"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"រួចរាល់"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ប្ដូររបៀប"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"ដោះសោ"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"ម៉ាស៊ីនថត"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"ស្ងាត់"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"បើកសំឡេង"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"រុញឡើងលើដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"រុញចុះក្រោមសម្រាប់ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"រុញទៅឆ្វេងដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"រុញទៅស្ដាំដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
+ <string name="user_switched" msgid="3768006783166984410">"អ្នកប្រើបច្ចុប្បន្ន <xliff:g id="NAME">%1$s</xliff:g> ។"</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"ការហៅពេលអាសន្ន"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ភ្លេចលំនាំ"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"លំនាំមិនត្រឹមត្រូវ"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"ពាក្យសម្ងាត់មិនត្រឹមត្រូវ"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"កូដ PIN មិនត្រឹមត្រូវ"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER">%d</xliff:g> វិនាទី។"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"គូរលំនាំរបស់អ្នក"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"បញ្ចូលកូដ PIN ស៊ីមកាត"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"បញ្ចូលកូដ PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"បញ្ចូលពាក្យសម្ងាត់"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"ឥឡូវស៊ីមកាតត្រូវបានបិទ។ បញ្ចូលកូដ PUK ដើម្បីបន្ត។ ចំពោះព័ត៌មានលម្អិតទាក់ទងក្រុមហ៊ុនបញ្ជូនរបស់អ្នក។"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"បញ្ចូលកូដ PIN ដែលចង់បាន"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"បញ្ជាក់កូដ PIN ដែលចង់បាន"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"កំពុងដោះសោស៊ីមកាត..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"កូដ PIN មិនត្រឹមត្រូវ។"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"បញ្ចូលកូដ PIN ដែលមានពី ៤ ដល់ ៨ លេខ។"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"កូដ PUK គួរតែមាន ៨ លេខ ឬច្រើនជាងនេះ។"</string>
+ <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_login_instructions" msgid="1100551261265506448">"ដើម្បីដោះសោ ចូលក្នុងគណនី Google ។"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"ឈ្មោះអ្នកប្រើ (អ៊ីម៉ែល)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"ចូល"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"ឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់មិនត្រឹមត្រូវ។"</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ភ្លេចឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់របស់អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"កំពុងពិនិត្យមើលគណនី..."</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="1575557200627128949">"អ្នកបានព្យាយាមដោះសោកុំព្យូទ័របន្ទះមិនត្រឹមត្រូវចំនួន <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="4051015943038199910">"អ្នកបានព្យាយាមដោះសោទូរស័ព្ទមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាមមិនជោគជ័យច្រើនជាង <xliff:g id="NUMBER_1">%d</xliff:g> ដង ទូរស័ព្ទនឹងត្រូវបានកំណត់ទៅលំនាំដើមដូចចេញពីរោងចក្រ ហើយទិន្នន័យអ្នកប្រើនឹងបាត់បង់។"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"អ្នកបានព្យាយាមដោះសោកុំព្យូទ័របន្ទះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង។ កុំព្យូទ័របន្ទះនឹងត្រូវបានកំណត់ទៅលំនាំដើមដូចចេញពីរោងចក្រ"</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"អ្នកបានព្យាយាមដោះសោទូរស័ព្ទមិនត្រឹមត្រូវចំនួន <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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"លុបចេញ"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ប៊ូតុងបទមុន"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ប៊ូតុងបទបន្ទាប់"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ប៊ូតុងផ្អាក"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ប៊ូតុងចាក់"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ប៊ូតុងបញ្ឈប់"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"គ្មានសេវា។"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..0dcb7d1
--- /dev/null
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"ພິມລະຫັດ PIN"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"ພິມລະຫັດ PUK ແລະລະຫັດ PIN ອັນໃໝ່"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"ລະຫັດ PUK"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"ລະຫັດ PIN ໃໝ່"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"ແຕະເພື່ອພິມລະຫັດຜ່ານ"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ພິມລະຫັດເພື່ອປົດລັອກ"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ພິມລະຫັດ PIN ເພື່ອປົດລັອກ"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"ເພື່ອປົດລັອກ, ໃຫ້ກົດເມນູ ແລ້ວກົດ 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"ຄວາມພະຍາຍາມປົດລັອກດ້ວຍໜ້ານັ້ນ ເກີນຈຳນວນທີ່ກຳນົດແລ້ວ"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"ສາກເຕັມແລ້ວ"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"ກຳລັງສາກ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"ເຊື່ອມຕໍ່ອຸປະກອນສາກຂອງທ່ານ."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"ກົດເມນູເພື່ອປົດລັອກ."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"ເຄືອຂ່າຍຖືກລັອກ"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"ບໍ່ມີຊິມກາດ"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"ບໍ່ມີຊິມກາດໃນແທັບເລັດ."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"ບໍ່ມີຊິມກາດຢູ່ໃນໂທລະສັບ."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"ໃສ່ SIM card."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"ບໍ່ພົບເຫັນຊິມກາດ ຫຼືບໍ່ສາມາດອ່ານຊິມກາດໄດ້. ກະລຸນາໃສ່ຊິມກາດໃໝ່."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM card ບໍ່ສາມາດໃຊ້ໄດ້."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM card ຂອງທ່ານຖືກປິດການນຳໃຊ້ຢ່າງຖາວອນແລ້ວ.\n ຕິດຕໍ່ຜູ່ໃຫ້ບໍລິການລະບົບຂອງທ່ານເພື່ອຂໍ SIM card ໃໝ່."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ຊິມກາດຖືກລັອກ."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ຊິມກາດຖືກລັອກດ້ວຍລະຫັດ PUK."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"ກຳລັງປົດລັອກຊິມກາດ..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ວິດເຈັດ %2$d ຈາກທັງໝົດ %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ເພີ່ມວິດເຈັດ"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ຫວ່າງເປົ່າ"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"ຂະຫຍາຍພື້ນທີ່ປົດລັອກແລ້ວ."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"ຫຍໍ້ພື້ນທີ່ປົດລັອກແລ້ວ."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ວິດເຈັດ."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ໂຕເລືອກຂອງຜູ່ໃຊ້"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"ສະຖານະ"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ກ້ອງ"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"ການຄວບຄຸມສື່"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ການຈັດຮຽງວິເຈັດໃໝ່ເລີ່ມຕົ້ນແລ້ວ."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ການຈັດຮຽງວິດເຈັດຄືນໃໝ່ສຳເລັດແລ້ວ."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ລຶບວິດເຈັດ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ແລ້ວ."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ຂະຫຍາຍຂອບເຂດປົດລັອກ."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ການປົດລັອກດ້ວຍການເລື່ອນ."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ປົດລັອກດ້ວຍຮູບແບບ."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ປົດລັອກດ້ວຍໜ້າ."</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ປົດລັອກດ້ວຍ PIN."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"ການປົດລັອກດ້ວຍລະຫັດຜ່ານ."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"ພື້ນທີ່ຮູບແບບ."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"ເລື່ອນພື້ນທີ່."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ປຸ່ມເພງກ່ອນໜ້າ"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ປຸ່ມເພງຕໍ່ໄປ"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ປຸ່ມຢຸດຊົ່ວຄາວ"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ປຸ່ມຫຼິ້ນ"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ປຸ່ມຢຸດ"</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="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ຍົກເລີກ"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ລຶບ"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ແລ້ວໆ"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ປ່ຽນຮູບແບບ"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"ປົດລັອກ"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"ກ້ອງ"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"ປິດສຽງ"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"ເປີດສຽງ"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"ເລື່ອນລົງເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"ເລື່ອນໄປທາງຊ້າຍເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"ເລື່ອນໄປທາງຂວາເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"ຜູ່ໃຊ້ປັດຈຸບັນ <xliff:g id="NAME">%1$s</xliff:g> ."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"ການໂທສຸກເສີນ"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ລືມຮູບແບບປົດລັອກ?"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"ຮູບແບບຜິດ"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"ລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"ລະຫັດ PIN ຜິດ"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"ລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER">%d</xliff:g> ວິນາທີ."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"ແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານ"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"ໃສ່ລະຫັດ PIN ຂອງຊິມ"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"ໃສ່ລະຫັດ PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"ໃສ່ລະຫັດຜ່ານ"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"ຊິມຖືກປິດການນຳໃຊ້ແລ້ວ. ປ້ອນລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ຕິດຕໍ່ຜູ່ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"ໃສ່ລະຫັດ PIN ທີ່ຕ້ອງການ."</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"ຢືນຢັນລະຫັດ PIN ທີ່ຕ້ອງການ"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ປົດລັອກ SIM card..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ພິມລະຫັດ PIN ຄວາມຍາວ 4 ເຖິງ 8 ໂຕເລກ."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"ລະຫັດ PUK ຄວນມີຢ່າງໜ້ອຍ 8 ໂຕເລກ."</string>
+ <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_login_instructions" msgid="1100551261265506448">"ເພື່ອປົດລັອກ, ເຂົ້າສູ່ລະບົບດ້ວຍບັນຊີ Google ຂອງທ່ານ."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"ຊື່ຜູ່ໃຊ້ (ອີເມວ)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"ລະຫັດຜ່ານ"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"ເຂົ້າສູ່ລະບົບ"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"ຊື່ຜູ່ໃຊ້ ຫຼືລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ລືມຊື່ຜູ່ໃຊ້ ຫຼືລະຫັດຜ່ານຂອງທ່ານບໍ່?\nໄປທີ່ "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"ກຳລັງກວດສອບບັນຊີ..."</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="1575557200627128949">"ທ່ານໄດ້ພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ສຳເລັດ <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="4051015943038199910">"ທ່ານໄດ້ພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ສຳເລັດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ ໂທລະສັບຂອງທ່ານຈະຖືກຕັ້ງ ໃຫ້ກັບໄປໃຊ້ຄ່າເລີ່ມຕົ້ນຈາກໂຮງງານຄືນໃໝ່ ແລະຂໍ້ມູນຜູ່ໃຊ້ທັງໝົດຈະສູນຫາຍໄປ."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"ທ່ານໄດ້ພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ສຳເລັດ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອແລ້ວ. ຕອນນີ້ແທັບເລັດຈະຖືກຕັ້ງໃຫ້ກັບໄປໃຊ້ຄ່າເລີ່ມຕົ້ນຈາກໂຮງງານ."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"ທ່ານໄດ້ພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກ <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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ລຶບອອກ"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ປຸ່ມເພງກ່ອນໜ້າ"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ປຸ່ມເພງຕໍ່ໄປ"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ປຸ່ມຢຸດຊົ່ວຄາວ"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ປຸ່ມຫຼິ້ນ"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ປຸ່ມຢຸດ"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"ບໍ່ມີບໍລິການ"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..4ae7220
--- /dev/null
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN кодыг бичнэ үү"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK-г бичээд шинэ PIN код оруулна уу"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK код"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Шинэ PIN код"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Нууц үг бичих бол хүрнэ үү"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Тайлах нууц үгийг бичнэ үү"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Тайлах PIN-г оруулна уу"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Буруу PIN код."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Тайлах бол Цэсийг дараад 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Нүүрээр түгжээ тайлах оролдлогын тоо дээд хэмжээнээс хэтэрсэн"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Цэнэглэгдэв"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Цэнэглэж байна, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Цэнэглэгчээ холбоно уу."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Тайлх бол цэсийг дарна уу."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Сүлжээ түгжигдсэн"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"SIM карт байхгүй"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Таблет SIM картгүй."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Утсанд SIM карт байхгүй."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"SIM картыг оруулна уу."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM карт байхгүй эсвэл унших боломжгүй. SIM карт оруулна уу."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Ашиглаж болохгүй SIM карт."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Таны SIM карт бүрмөсөн идэвхгүй болов.\n Өөр SIM карт авах бол өөрийн утасгүй үйлчилгээний нийлүүлэгчтэй холбогдоно уу."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM карт түгжигдсэн."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM картны PUK-түгжигдсэн."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM картны түгжээг гаргаж байна…"</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d. -н %2$d виджет"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Виджет нэмэх."</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Хоосон"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Тайлах хэсэг нээгдсэн."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Тайлах хэсэг хаагдсан."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виджет."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Хэрэглэгч сонгоч"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Статус"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камер"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Медиа контрол"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Виджет дахин эрэмбэлж эхлэв."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Виджетийг дахин эрэмбэлж дуусав."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виджет устсан."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Түгжээгүй хэсгийг өргөсгөх."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Тайлах гулсуулалт."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Тайлах хээ."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Нүүрээр тайлах"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Тайлах пин."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Тайлах нууц үг."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Хээний хэсэг."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Гулсуулах хэсэг."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Өмнөх бичлэг товч"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Дараагийн бичлэг товч"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Түр зогсоох товч"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Тоглуулах товч"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Зогсоох товч"</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Цуцлах"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Устгах"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Дуусгах"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Горим өөрчлөх"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Шифт"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Оруулах"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Тайлах"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Камер"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Чимээгүй"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Дуунууд идэвхтэй"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Хайх"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-г гулсуулах."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> хийх бол доош гулсуулах."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> хийх зүүнлүү гулсуулах."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> хийх бол баруунлуу гулсуулах."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Одоогийн хэрэглэгч <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Яаралтай дуудлага"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Хээг мартсан"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Буруу хээ"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Нууц үг буруу"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN буруу"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Хээг зурах"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN оруулна уу"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN оруулна уу"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Нууц үгээ оруулна уу"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM идэвхгүй байна. Үргэлжлүүлэх бол PUK кодыг оруулна уу. Дэлгэрэнгүй мэдээллийг оператороос асууна ууу"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Хүссэн PIN кодоо оруулна уу"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Хүссэн PIN кодоо дахин оруулна уу"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM картны түгжээг гаргаж байна…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Буруу PIN код."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4-8 тооноос бүтэх PIN-г бичнэ үү."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK код 8-с цөөнгүй тооноос бүтнэ."</string>
+ <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_login_instructions" msgid="1100551261265506448">"Түгжээг тайлах бол Google акаунтаараа нэвтэрнэ үү."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Хэрэглэгчийн нэр (имэйл)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Нууц үг"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Нэвтрэх"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Хэрэглэгчийн нэр эсвэл нууц үг буруу."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Хэрэглэгчийн нэр нууц үгээ мартсан уу?\n"<b>"google.com/accounts/recovery"</b>"-д зочилно уу."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Акаунт шалгаж байна…"</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="1575557200627128949">"Та таблетыг тайлах гэж <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="4051015943038199910">"Та утсыг тайлах гэж <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу оролдлоо. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оролдвол утас үйлдвэрийн үндсэн утгаараа тохируулагдах ба хэрэглэгчийн дата бүхэлдээ устана."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Та таблетыг тайлах гэж <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оролдлоо. Таблет одоо үйлдвэрийн үндсэн утгаараа тохируулагдах болно."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Та утсыг тайлах гэж <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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Устгах"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Өмнөх дуу товч"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Дараагийн дуу товч"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Түр зогсох товч"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Тоглуулах товч"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Зогсоох товч"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Үйлчилгээ байхгүй."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..0aeeeb5
--- /dev/null
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Taip kod PIN"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Taip PUK dan kod PIN baharu"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"Kod PUK"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Kod PIN Baharu"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Sentuh untuk menaip kata laluan"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Taip kata laluan untuk membuka kunci"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Taip PIN untuk membuka kunci"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Kod PIN salah."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Untuk membuka kunci, tekan Menu, kemudian 0."</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Telah melepasi had cubaan Buka Kunci Wajah"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Sudah dicas"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"Mengecas, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Sambungkan pengecas anda."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Tekan Menu untuk membuka kunci."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Rangkaian dikunci"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Tiada kad SIM"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Tiada kad SIM dalam tablet."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Tiada kad SIM dalam telefon."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Masukkan kad SIM."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"Kad SIM tiada atau tidak boleh dibaca. Sila masukkan kad SIM."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Kad SIM tidak boleh digunakan."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Kad SIM anda telah dilumpuhkan secara kekal.\n Hubungi pembekal perkhidmatan wayarles anda untuk mendapatkan kad SIM lain."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Kad SIM dikunci."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Kad SIM dikunci dengan PUK."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Membuka kunci kad SIM..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d dari %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Tambah widget."</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Kosong"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Bahagian buka kunci dikembangkan."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Bahagian buka kunci diruntuhkan."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Pemilih pengguna"</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">"Kawalan media"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Penyusunan semula widget dimulakan."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Penyusunan semula widget tamat."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> dipadamkan."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Kembangkan bahagian buka kunci."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Buka kunci luncur."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Buka kunci corak."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Wajah Buka Kunci"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Buka kunci pin."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Buka kunci kata laluan."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Kawasan corak."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Kawasan luncur."</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Butang lagu sebelumnya"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Butang lagu seterusnya"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Butang jeda"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Butang main"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Butang berhenti"</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="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Padam"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Selesai"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Perubahan mod"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Masuk"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"Buka kunci"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"Senyap"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"Bunyi dihidupkan"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Carian"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Luncurkan ke bawah untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Luncurkan ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Luncurkan ke kanan untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan kecemasan"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Corak"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Corak Salah"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Kata Laluan Salah"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN salah"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Cuba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> saat."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Lukiskan corak anda"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Masukkan Kata Laluan"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Hubungi pembawa untuk butiran."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Masukkan kod PIN yang diingini"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Sahkan kod PIN yang diingini"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kad SIM..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kod PIN salah."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Kod PUK mestilah 8 nombor atau lebih."</string>
+ <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_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, log masuk dengan akaun Google anda."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Nama Pengguna (E-mel)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Kata laluan"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Log masuk"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau kata laluan tidak sah."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau kata laluan anda?\nLawati"<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Menyemak akaun…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN anda secara 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 anda secara 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="1575557200627128949">"Anda telah mencuba untuk membuka kunci tablet dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, tablet akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Anda telah mencuba untuk membuka kunci telefon dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, telefon akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Anda telah mencuba untuk membuka kunci tablet secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet kini akan ditetapkan semula ke tetapan lalai kilang."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Anda telah mencuba untuk membuka kunci telefon secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon kini akan ditetapkan semula ke tetapan lalai kilang."</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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alih keluar"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Butang lagu sebelumnya"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Butang lagu seterusnya"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Butang jeda"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Butang main"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Butang berhenti"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tiada perkhidmatan."</string>
+</resources>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index 664b85e..937d029 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -134,5 +134,5 @@
<string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Дугме за паузу"</string>
<string name="keyguard_transport_play_description" msgid="2924628863741150956">"Дугме за репродукцију"</string>
<string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Дугме за заустављање"</string>
- <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ван мреже сте."</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Офлајн сте."</string>
</resources>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..49953c0
--- /dev/null
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -0,0 +1,138 @@
+<?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="keyguard_password_enter_pin_code" msgid="3037685796058495017">"輸入 PIN 碼"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"輸入 PUK 碼和新 PIN 碼"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK 碼"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"新 PIN 碼"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"輕觸即可輸入密碼"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"輸入密碼即可解鎖"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"輸入 PIN 碼即可解鎖"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 碼不正確。"</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"如要解鎖,請按選單鍵,然後按 0。"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超過臉容解鎖嘗試次數上限"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"充電完成"</string>
+ <string name="keyguard_plugged_in" msgid="8117572000639998388">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"請連接充電器。"</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按選單鍵解鎖。"</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"網絡已鎖定"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"找不到 SIM 卡"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板電腦中沒有 SIM 卡。"</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手機中沒有 SIM 卡。"</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"請插入 SIM 卡。"</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"找不到 SIM 卡或無法讀取 SIM 卡,請插入 SIM 卡。"</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM 卡無法使用。"</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"您的 SIM 卡已被永久停用。\n請與您的無線服務供應商聯絡,以取得另一張 SIM 卡。"</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 卡處於鎖定狀態。"</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 卡處於 PUK 鎖定狀態。"</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解開上鎖的 SIM 卡..."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。第 %2$d 個小工具,共 %3$d 個。"</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"新增小工具。"</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"解鎖區域已展開。"</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"解鎖區域已收合。"</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具。"</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"用戶選取工具"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"狀態"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"相機"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒體控制"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"已開始為小工具重新排列次序。"</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"已完成為小工具重新排列次序。"</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具已刪除。"</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"展開解鎖區域。"</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"滑動解鎖。"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"圖案解鎖。"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"臉容解鎖。"</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN 解鎖。"</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"密碼解鎖。"</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"圖案區域。"</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"滑動區域。"</string>
+ <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"[上一首曲目] 按鈕"</string>
+ <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"[下一首曲目] 按鈕"</string>
+ <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"[暫停] 按鈕"</string>
+ <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"[播放] 按鈕"</string>
+ <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"[停止] 按鈕"</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="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"刪除"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"完成"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"模式更改"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 鍵"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 鍵"</string>
+ <string name="description_target_unlock" msgid="2228524900439801453">"解鎖"</string>
+ <string name="description_target_camera" msgid="969071997552486814">"相機"</string>
+ <string name="description_target_silent" msgid="893551287746522182">"靜音"</string>
+ <string name="description_target_soundon" msgid="30052466675500172">"音效已開啟"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"向下滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"向左滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"向右滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="user_switched" msgid="3768006783166984410">"目前的用戶是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖案"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"圖案錯誤"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"密碼錯誤"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 錯誤"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"請在 <xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"畫出圖案"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"輸入 SIM 卡 PIN 碼"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"輸入 PIN 碼"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"輸入密碼"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM 卡現已停用,請輸入 PUK 碼以繼續。詳情請與流動網絡供應商聯絡。"</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"輸入所需的 PIN 碼"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"確認所需的 PIN 碼"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解開上鎖的 SIM 卡..."</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 碼不正確。"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"請輸入一個 4 至 8 位數的 PIN 碼。"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK 碼應由 8 個或以上數字組成。"</string>
+ <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_login_instructions" msgid="1100551261265506448">"如要解鎖,請以 Google 帳戶登入。"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"用戶名稱 (電子郵件)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"密碼"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"登入"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"無效的用戶名稱或密碼。"</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘記用戶名稱或密碼?\n請瀏覽 "<b>"google.com/accounts/recovery"</b>"。"</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"正在檢查帳戶…"</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="1575557200627128949">"您嘗試了 <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="4051015943038199910">"您嘗試了 <xliff:g id="NUMBER_0">%d</xliff:g> 次仍未能成功解開這部上鎖的手機。如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,手機將回復原廠設定,所有用戶資料均會失去。"</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"您嘗試了 <xliff:g id="NUMBER">%d</xliff:g> 次仍未能成功解開這部上鎖的平板電腦。平板電腦現在將回復原廠設定。"</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"您嘗試了 <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_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
+ <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"[上一首曲目] 按鈕"</string>
+ <string name="keyguard_transport_next_description" msgid="4299258300283778305">"[下一首曲目] 按鈕"</string>
+ <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"[暫停] 按鈕"</string>
+ <string name="keyguard_transport_play_description" msgid="2924628863741150956">"[播放] 按鈕"</string>
+ <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"[停止] 按鈕"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
+</resources>
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 83ec1ad..1e6954e 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -22,22 +22,29 @@
android:versionCode="1">
<!-- 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.
- -->
+ on the device. Usually an app can access only the print jobs it created. -->
<permission
android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"
android:label="@string/permlab_accessAllPrintJobs"
android:description="@string/permdesc_accessAllPrintJobs"
android:protectionLevel="signature" />
+ <!-- May be required by the settings and add printer activities of a
+ print service if the developer wants only trusted system code to
+ be able to launch these activities. -->
+ <permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+ android:label="@string/permlab_startPrintServiceConfigActivity"
+ android:description="@string/permdesc_startPrintServiceConfigActivity"
+ android:protectionLevel="signature" />
+
<uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/>
- <uses-permission android:name="android.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-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/>
<application
- android:allowClearUserData="false"
+ android:allowClearUserData="true"
android:label="@string/app_label"
android:allowBackup= "false"
android:supportsRtl="true">
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 235a7a1..543c425 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -139,10 +139,20 @@
<!-- Title of an application permission, listed so the user can choose whether they want
to allow the application to do this. -->
- <string name="permlab_accessAllPrintJobs">access all print jobs</string>
+ <string name="permlab_accessAllPrintJobs" translatable="false">access all print jobs</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_accessAllPrintJobs">Allows the holder to access print jobs
- created by another app. Should never be needed for normal apps.</string>
+ <string name="permdesc_accessAllPrintJobs" translatable="false">Allows the holder to access
+ print jobs created by another app. Should never be needed for normal apps.</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_startPrintServiceConfigActivity" translatable="false">start print
+ service configuration activities</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_startPrintServiceConfigActivity" translatable="false">Allows the
+ holder to start the configuration activities of a print service. Should never be needed
+ for normal apps.</string>
</resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
index 43a751c..829fb06 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
@@ -23,13 +23,13 @@
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.print.IPrintManager;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.text.TextUtils;
@@ -40,12 +40,13 @@
* based on print job state transitions.
*/
public class NotificationController {
- public static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+ public static final boolean DEBUG = false;
public static final String LOG_TAG = "NotificationController";
private static final String INTENT_ACTION_CANCEL_PRINTJOB = "INTENT_ACTION_CANCEL_PRINTJOB";
private static final String INTENT_ACTION_RESTART_PRINTJOB = "INTENT_ACTION_RESTART_PRINTJOB";
+
private static final String INTENT_EXTRA_PRINTJOB_ID = "INTENT_EXTRA_PRINTJOB_ID";
private static final String INTENT_EXTRA_PRINTJOB_LABEL = "INTENT_EXTRA_PRINTJOB_LABEL";
private static final String INTENT_EXTRA_PRINTER_NAME = "INTENT_EXTRA_PRINTER_NAME";
@@ -61,8 +62,9 @@
public void onPrintJobStateChanged(PrintJobInfo printJob) {
if (DEBUG) {
- Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: " + printJob.getId()
- + " state:" + PrintJobInfo.stateToString(printJob.getState()));
+ Log.i(LOG_TAG, "onPrintJobStateChanged() printJobId: "
+ + printJob.getId().flattenToString() + " state:"
+ + PrintJobInfo.stateToString(printJob.getState()));
}
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
@@ -96,7 +98,7 @@
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
private void createFailedNotification(PrintJobInfo printJob) {
@@ -115,7 +117,7 @@
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
private void createBlockedNotification(PrintJobInfo printJob) {
@@ -132,25 +134,25 @@
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
- private void removeNotification(int printJobId) {
- mNotificationManager.cancel(printJobId);
+ private void removeNotification(PrintJobId printJobId) {
+ mNotificationManager.cancel(printJobId.flattenToString(), 0);
}
private PendingIntent createCancelIntent(PrintJobInfo printJob) {
Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
- intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + String.valueOf(printJob.getId()));
+ intent.setAction(INTENT_ACTION_CANCEL_PRINTJOB + "_" + printJob.getId().flattenToString());
intent.putExtra(INTENT_EXTRA_PRINTJOB_ID, printJob.getId());
intent.putExtra(INTENT_EXTRA_PRINTJOB_LABEL, printJob.getLabel());
intent.putExtra(INTENT_EXTRA_PRINTER_NAME, printJob.getPrinterName());
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
- private PendingIntent createRestartIntent(int printJobId) {
+ private PendingIntent createRestartIntent(PrintJobId printJobId) {
Intent intent = new Intent(mContext, NotificationBroadcastReceiver.class);
- intent.setAction(INTENT_ACTION_RESTART_PRINTJOB + "_" + String.valueOf(printJobId));
+ intent.setAction(INTENT_ACTION_RESTART_PRINTJOB + "_" + printJobId.flattenToString());
intent.putExtra(INTENT_EXTRA_PRINTJOB_ID, printJobId);
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
@@ -162,17 +164,17 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null && action.startsWith(INTENT_ACTION_CANCEL_PRINTJOB)) {
- final int printJobId = intent.getExtras().getInt(INTENT_EXTRA_PRINTJOB_ID);
+ PrintJobId printJobId = intent.getExtras().getParcelable(INTENT_EXTRA_PRINTJOB_ID);
String printJobLabel = intent.getExtras().getString(INTENT_EXTRA_PRINTJOB_LABEL);
String printerName = intent.getExtras().getString(INTENT_EXTRA_PRINTER_NAME);
handleCancelPrintJob(context, printJobId, printJobLabel, printerName);
} else if (action != null && action.startsWith(INTENT_ACTION_RESTART_PRINTJOB)) {
- final int printJobId = intent.getExtras().getInt(INTENT_EXTRA_PRINTJOB_ID);
+ PrintJobId printJobId = intent.getExtras().getParcelable(INTENT_EXTRA_PRINTJOB_ID);
handleRestartPrintJob(context, printJobId);
}
}
- private void handleCancelPrintJob(final Context context, final int printJobId,
+ private void handleCancelPrintJob(final Context context, final PrintJobId printJobId,
final String printJobLabel, final String printerName) {
if (DEBUG) {
Log.i(LOG_TAG, "handleCancelPrintJob() printJobId:" + printJobId);
@@ -190,7 +192,7 @@
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setShowWhen(true);
- notificationManager.notify(printJobId, builder.build());
+ notificationManager.notify(printJobId.flattenToString(), 0, builder.build());
// Call into the print manager service off the main thread since
// the print manager service may end up binding to the print spooler
@@ -226,7 +228,7 @@
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
- private void handleRestartPrintJob(final Context context, final int printJobId) {
+ private void handleRestartPrintJob(final Context context, final PrintJobId printJobId) {
if (DEBUG) {
Log.i(LOG_TAG, "handleRestartPrintJob() printJobId:" + printJobId);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 5c3d700..4333aea 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -47,6 +47,7 @@
import android.print.PrintAttributes.Resolution;
import android.print.PrintDocumentAdapter;
import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterCapabilitiesInfo;
@@ -62,9 +63,11 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
+import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
@@ -102,8 +105,7 @@
private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
public static final String EXTRA_PRINT_DOCUMENT_ADAPTER = "printDocumentAdapter";
- public static final String EXTRA_PRINT_ATTRIBUTES = "printAttributes";
- public static final String EXTRA_PRINT_JOB_ID = "printJobId";
+ public static final String EXTRA_PRINT_JOB = "printJob";
public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
@@ -161,7 +163,7 @@
private Document mDocument;
private PrintController mController;
- private int mPrintJobId;
+ private PrintJobId mPrintJobId;
private IBinder mIPrintDocumentAdapter;
@@ -173,17 +175,18 @@
Bundle extras = getIntent().getExtras();
- mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
- if (mPrintJobId < 0) {
- throw new IllegalArgumentException("Invalid print job id: " + mPrintJobId);
+ PrintJobInfo printJob = extras.getParcelable(EXTRA_PRINT_JOB);
+ if (printJob == null) {
+ throw new IllegalArgumentException("printJob cannot be null");
}
+ mPrintJobId = printJob.getId();
mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINT_DOCUMENT_ADAPTER);
if (mIPrintDocumentAdapter == null) {
throw new IllegalArgumentException("PrintDocumentAdapter cannot be null");
}
- PrintAttributes attributes = getIntent().getParcelableExtra(EXTRA_PRINT_ATTRIBUTES);
+ PrintAttributes attributes = printJob.getAttributes();
if (attributes != null) {
mCurrPrintAttributes.copyFrom(attributes);
}
@@ -1371,7 +1374,8 @@
null, false);
// First animation - fade out the old content.
- hidingView.animate().alpha(0.0f).withLayer().withEndAction(new Runnable() {
+ AutoCancellingAnimator.animate(hidingView).alpha(0.0f)
+ .withLayer().withEndAction(new Runnable() {
@Override
public void run() {
hidingView.setVisibility(View.INVISIBLE);
@@ -1390,8 +1394,8 @@
/ (float) contentContainer.getHeight();
// Second animation - resize the container.
- contentContainer.animate().scaleY(scaleY).withLayer().withEndAction(
- new Runnable() {
+ AutoCancellingAnimator.animate(contentContainer).scaleY(scaleY).withLayer()
+ .withEndAction(new Runnable() {
@Override
public void run() {
// Swap the old and the new content.
@@ -1400,8 +1404,8 @@
contentContainer.addView(showingView);
// Third animation - show the new content.
- showingView.animate().withLayer().alpha(1.0f).withEndAction(
- new Runnable() {
+ AutoCancellingAnimator.animate(showingView).withLayer().alpha(1.0f)
+ .withEndAction(new Runnable() {
@Override
public void run() {
postAnimateCommand.run();
@@ -2212,4 +2216,67 @@
}
}
}
+
+ private static final class AutoCancellingAnimator
+ implements OnAttachStateChangeListener, Runnable {
+
+ private ViewPropertyAnimator mAnimator;
+
+ private boolean mCancelled;
+ private Runnable mEndCallback;
+
+ public static AutoCancellingAnimator animate(View view) {
+ ViewPropertyAnimator animator = view.animate();
+ AutoCancellingAnimator cancellingWrapper =
+ new AutoCancellingAnimator(animator);
+ view.addOnAttachStateChangeListener(cancellingWrapper);
+ return cancellingWrapper;
+ }
+
+ private AutoCancellingAnimator(ViewPropertyAnimator animator) {
+ mAnimator = animator;
+ }
+
+ public AutoCancellingAnimator alpha(float alpha) {
+ mAnimator = mAnimator.alpha(alpha);
+ return this;
+ }
+
+ public void cancel() {
+ mAnimator.cancel();
+ }
+
+ public AutoCancellingAnimator withLayer() {
+ mAnimator = mAnimator.withLayer();
+ return this;
+ }
+
+ public AutoCancellingAnimator withEndAction(Runnable callback) {
+ mEndCallback = callback;
+ mAnimator = mAnimator.withEndAction(this);
+ return this;
+ }
+
+ public AutoCancellingAnimator scaleY(float scale) {
+ mAnimator = mAnimator.scaleY(scale);
+ return this;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ cancel();
+ }
+
+ @Override
+ public void run() {
+ if (!mCancelled) {
+ mEndCallback.run();
+ }
+ }
+ }
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 8580fcd..a6353f7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -37,6 +37,7 @@
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
import android.print.PrintDocumentInfo;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterId;
@@ -51,6 +52,8 @@
import com.android.internal.os.SomeArgs;
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;
@@ -63,8 +66,6 @@
import java.util.ArrayList;
import java.util.List;
-import libcore.io.IoUtils;
-
/**
* Service for exposing some of the {@link PrintSpooler} functionality to
* another process.
@@ -73,7 +74,7 @@
private static final String LOG_TAG = "PrintSpoolerService";
- private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
+ private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = true;
private static final boolean DEBUG_PERSISTENCE = false;
@@ -91,10 +92,6 @@
private static PrintSpoolerService sInstance;
- private static int sPrintJobIdCounter;
-
- private Intent mStartPrintJobConfigActivityIntent;
-
private IPrintSpoolerClient mClient;
private HandlerCaller mHandlerCaller;
@@ -112,8 +109,6 @@
@Override
public void onCreate() {
super.onCreate();
- mStartPrintJobConfigActivityIntent = new Intent(PrintSpoolerService.this,
- PrintJobConfigActivity.class);
mHandlerCaller = new HandlerCaller(this, getMainLooper(),
new HandlerCallerCallback(), false);
@@ -147,7 +142,7 @@
}
@Override
- public void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback,
+ public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence) throws RemoteException {
PrintJobInfo printJob = null;
try {
@@ -159,38 +154,28 @@
@SuppressWarnings("deprecation")
@Override
- public void createPrintJob(String printJobName, IPrintClient client,
- IPrintDocumentAdapter printAdapter, PrintAttributes attributes,
- IPrintSpoolerCallbacks callback, int appId, int sequence)
- throws RemoteException {
- PrintJobInfo printJob = null;
- try {
- printJob = PrintSpoolerService.this.createPrintJob(
- printJobName, client, attributes, appId);
- if (printJob != null) {
- Intent intent = mStartPrintJobConfigActivityIntent;
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
- printAdapter.asBinder());
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB_ID,
- printJob.getId());
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_ATTRIBUTES, attributes);
+ public void createPrintJob(PrintJobInfo printJob, IPrintClient client,
+ IPrintDocumentAdapter printAdapter) throws RemoteException {
+ PrintSpoolerService.this.createPrintJob(printJob);
- IntentSender sender = PendingIntent.getActivity(
- PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
+ Intent intent = new Intent(printJob.getId().flattenToString());
+ intent.setClass(PrintSpoolerService.this, PrintJobConfigActivity.class);
+ intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
+ printAdapter.asBinder());
+ intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB, printJob);
- Message message = mHandlerCaller.obtainMessageOO(
- HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
- client, sender);
- mHandlerCaller.executeOrSendMessage(message);
- }
- } finally {
- callback.onCreatePrintJobResult(printJob, sequence);
- }
+ IntentSender sender = PendingIntent.getActivity(
+ PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
+
+ Message message = mHandlerCaller.obtainMessageOO(
+ HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
+ client, sender);
+ mHandlerCaller.executeOrSendMessage(message);
}
@Override
- public void setPrintJobState(int printJobId, int state, String error,
+ public void setPrintJobState(PrintJobId printJobId, int state, String error,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
@@ -202,7 +187,7 @@
}
@Override
- public void setPrintJobTag(int printJobId, String tag,
+ public void setPrintJobTag(PrintJobId printJobId, String tag,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
@@ -213,7 +198,7 @@
}
@Override
- public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
PrintSpoolerService.this.writePrintJobData(fd, printJobId);
}
@@ -223,6 +208,16 @@
HandlerCallerCallback.MSG_SET_CLIENT, client);
mHandlerCaller.executeOrSendMessage(message);
}
+
+ @Override
+ public void removeObsoletePrintJobs() {
+ PrintSpoolerService.this.removeObsoletePrintJobs();
+ }
+
+ @Override
+ public void forgetPrintJobs(List<PrintJobId> printJobIds) {
+ PrintSpoolerService.this.forgetPrintJobs(printJobIds);
+ }
};
}
@@ -351,15 +346,16 @@
private boolean isStateVisibleToUser(int state) {
return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED
- || state == PrintJobInfo.STATE_COMPLETED|| state == PrintJobInfo.STATE_CANCELED));
+ || state == PrintJobInfo.STATE_COMPLETED || state == PrintJobInfo.STATE_CANCELED
+ || state == PrintJobInfo.STATE_BLOCKED));
}
- public PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
synchronized (mLock) {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
- if (printJob.getId() == printJobId
+ if (printJob.getId().equals(printJobId)
&& (appId == PrintManager.APP_ID_ANY
|| appId == printJob.getAppId())) {
return printJob;
@@ -369,20 +365,9 @@
}
}
- public PrintJobInfo createPrintJob(String label, IPrintClient client,
- PrintAttributes attributes, int appId) {
+ public void createPrintJob(PrintJobInfo printJob) {
synchronized (mLock) {
- final int printJobId = generatePrintJobIdLocked();
- PrintJobInfo printJob = new PrintJobInfo();
- printJob.setId(printJobId);
- printJob.setAppId(appId);
- printJob.setLabel(label);
- printJob.setAttributes(attributes);
- printJob.setState(PrintJobInfo.STATE_CREATED);
-
addPrintJobLocked(printJob);
-
- return printJob;
}
}
@@ -404,8 +389,7 @@
// decide whether to restart the job or just cancel it.
setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
getString(R.string.no_connection_to_printer));
- }
- break;
+ } break;
}
}
}
@@ -418,26 +402,7 @@
}
}
- private int generatePrintJobIdLocked() {
- int printJobId = sPrintJobIdCounter++;
- while (isDuplicatePrintJobId(printJobId)) {
- printJobId = sPrintJobIdCounter++;
- }
- return printJobId;
- }
-
- private boolean isDuplicatePrintJobId(int printJobId) {
- final int printJobCount = mPrintJobs.size();
- for (int j = 0; j < printJobCount; j++) {
- PrintJobInfo printJob = mPrintJobs.get(j);
- if (printJob.getId() == printJobId) {
- return true;
- }
- }
- return false;
- }
-
- public void writePrintJobData(final ParcelFileDescriptor fd, final int printJobId) {
+ public void writePrintJobData(final ParcelFileDescriptor fd, final PrintJobId printJobId) {
final PrintJobInfo printJob;
synchronized (mLock) {
printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
@@ -476,9 +441,9 @@
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
- public File generateFileForPrintJob(int printJobId) {
+ public File generateFileForPrintJob(PrintJobId printJobId) {
return new File(getFilesDir(), "print_job_"
- + printJobId + "." + PRINT_FILE_EXTENSION);
+ + printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
}
private void addPrintJobLocked(PrintJobInfo printJob) {
@@ -488,16 +453,59 @@
}
}
- private void removePrintJobLocked(PrintJobInfo printJob) {
- if (mPrintJobs.remove(printJob)) {
- generateFileForPrintJob(printJob.getId()).delete();
- if (DEBUG_PRINT_JOB_LIFECYCLE) {
- Slog.i(LOG_TAG, "[REMOVE] " + printJob);
+ private void forgetPrintJobs(List<PrintJobId> printJobIds) {
+ synchronized (mLock) {
+ boolean printJobsRemoved = false;
+ final int removedPrintJobCount = printJobIds.size();
+ for (int i = 0; i < removedPrintJobCount; i++) {
+ PrintJobId removedPrintJobId = printJobIds.get(i);
+ final int printJobCount = mPrintJobs.size();
+ for (int j = printJobCount - 1; j >= 0; j--) {
+ PrintJobInfo printJob = mPrintJobs.get(j);
+ if (removedPrintJobId.equals(printJob.getId())) {
+ mPrintJobs.remove(j);
+ printJobsRemoved = true;
+ if (DEBUG_PRINT_JOB_LIFECYCLE) {
+ Slog.i(LOG_TAG, "[FORGOT] " + printJob.getId().flattenToString());
+ }
+ removePrintJobFileLocked(printJob.getId());
+ }
+ }
+ }
+ if (printJobsRemoved) {
+ mPersistanceManager.writeStateLocked();
}
}
}
- public boolean setPrintJobState(int printJobId, int state, String error) {
+ private void removeObsoletePrintJobs() {
+ synchronized (mLock) {
+ final int printJobCount = mPrintJobs.size();
+ for (int i = printJobCount - 1; i >= 0; i--) {
+ PrintJobInfo printJob = mPrintJobs.get(i);
+ if (isObsoleteState(printJob.getState())) {
+ mPrintJobs.remove(i);
+ if (DEBUG_PRINT_JOB_LIFECYCLE) {
+ Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
+ }
+ removePrintJobFileLocked(printJob.getId());
+ }
+ }
+ mPersistanceManager.writeStateLocked();
+ }
+ }
+
+ private void removePrintJobFileLocked(PrintJobId printJobId) {
+ File file = generateFileForPrintJob(printJobId);
+ if (file.exists()) {
+ file.delete();
+ if (DEBUG_PRINT_JOB_LIFECYCLE) {
+ Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId.flattenToString());
+ }
+ }
+ }
+
+ public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
boolean success = false;
synchronized (mLock) {
@@ -516,7 +524,11 @@
switch (state) {
case PrintJobInfo.STATE_COMPLETED:
case PrintJobInfo.STATE_CANCELED:
- removePrintJobLocked(printJob);
+ // Just remove the file but keep the print job info since
+ // the app that created it may be holding onto the PrintJob
+ // instance and query it for its most recent state. We will
+ // remove the info for this job when told so by the system.
+ removePrintJobFileLocked(printJob.getId());
// $fall-through$
case PrintJobInfo.STATE_FAILED: {
@@ -570,6 +582,11 @@
return false;
}
+ private boolean isObsoleteState(int printJobState) {
+ return (isTeminalState(printJobState)
+ || printJobState == PrintJobInfo.STATE_QUEUED);
+ }
+
private boolean isActiveState(int printJobState) {
return printJobState == PrintJobInfo.STATE_CREATED
|| printJobState == PrintJobInfo.STATE_QUEUED
@@ -577,7 +594,12 @@
|| printJobState == PrintJobInfo.STATE_BLOCKED;
}
- public boolean setPrintJobTag(int printJobId, String tag) {
+ private boolean isTeminalState(int printJobState) {
+ return printJobState == PrintJobInfo.STATE_COMPLETED
+ || printJobState == PrintJobInfo.STATE_CANCELED;
+ }
+
+ public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -599,7 +621,7 @@
return false;
}
- public void setPrintJobCopiesNoPersistence(int printJobId, int copies) {
+ public void setPrintJobCopiesNoPersistence(PrintJobId printJobId, int copies) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -608,7 +630,8 @@
}
}
- public void setPrintJobPrintDocumentInfoNoPersistence(int printJobId, PrintDocumentInfo info) {
+ public void setPrintJobPrintDocumentInfoNoPersistence(PrintJobId printJobId,
+ PrintDocumentInfo info) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -617,7 +640,8 @@
}
}
- public void setPrintJobAttributesNoPersistence(int printJobId, PrintAttributes attributes) {
+ public void setPrintJobAttributesNoPersistence(PrintJobId printJobId,
+ PrintAttributes attributes) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -626,7 +650,7 @@
}
}
- public void setPrintJobPrinterNoPersistence(int printJobId, PrinterInfo printer) {
+ public void setPrintJobPrinterNoPersistence(PrintJobId printJobId, PrinterInfo printer) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -636,7 +660,7 @@
}
}
- public void setPrintJobPagesNoPersistence(int printJobId, PageRange[] pages) {
+ public void setPrintJobPagesNoPersistence(PrintJobId printJobId, PageRange[] pages) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
@@ -759,15 +783,9 @@
for (int j = 0; j < printJobCount; j++) {
PrintJobInfo printJob = printJobs.get(j);
- final int state = printJob.getState();
- if (state < PrintJobInfo.STATE_QUEUED
- || state > PrintJobInfo.STATE_CANCELED) {
- continue;
- }
-
serializer.startTag(null, TAG_JOB);
- serializer.attribute(null, ATTR_ID, String.valueOf(printJob.getId()));
+ serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString());
serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState()));
serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId()));
@@ -948,7 +966,8 @@
PrintJobInfo printJob = new PrintJobInfo();
- final int printJobId = Integer.parseInt(parser.getAttributeValue(null, ATTR_ID));
+ PrintJobId printJobId = PrintJobId.unflattenFromString(
+ parser.getAttributeValue(null, ATTR_ID));
printJob.setId(printJobId);
String label = parser.getAttributeValue(null, ATTR_LABEL);
printJob.setLabel(label);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
index 9ca3a86..c397c40 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
@@ -24,20 +24,26 @@
import android.app.FragmentTransaction;
import android.app.ListFragment;
import android.app.LoaderManager;
+import android.content.ActivityNotFoundException;
import android.content.ComponentName;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Bundle;
+import android.print.PrintManager;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
import android.text.TextUtils;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -59,6 +65,8 @@
*/
public final class SelectPrinterFragment extends ListFragment {
+ private static final String LOG_TAG = "SelectPrinterFragment";
+
private static final int LOADER_ID_PRINTERS_LOADER = 1;
private static final String FRAGMRNT_TAG_ADD_PRINTER_DIALOG =
@@ -142,40 +150,45 @@
private void updateAddPrintersAdapter() {
mAddPrinterServices.clear();
- // Get all print services.
- List<ResolveInfo> resolveInfos = getActivity().getPackageManager().queryIntentServices(
- new Intent(android.printservice.PrintService.SERVICE_INTERFACE),
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+ // Get all enabled print services.
+ PrintManager printManager = (PrintManager) getActivity()
+ .getSystemService(Context.PRINT_SERVICE);
+ List<PrintServiceInfo> enabledServices = printManager.getEnabledPrintServices();
- // No print services - done.
- if (resolveInfos.isEmpty()) {
+ // No enabled print services - done.
+ if (enabledServices.isEmpty()) {
return;
}
// Find the services with valid add printers activities.
- final int resolveInfoCount = resolveInfos.size();
- for (int i = 0; i < resolveInfoCount; i++) {
- ResolveInfo resolveInfo = resolveInfos.get(i);
-
- PrintServiceInfo printServiceInfo = PrintServiceInfo.create(
- resolveInfo, getActivity());
- String addPrintersActivity = printServiceInfo.getAddPrintersActivityName();
+ final int enabledServiceCount = enabledServices.size();
+ for (int i = 0; i < enabledServiceCount; i++) {
+ PrintServiceInfo enabledService = enabledServices.get(i);
// No add printers activity declared - done.
- if (TextUtils.isEmpty(addPrintersActivity)) {
+ if (TextUtils.isEmpty(enabledService.getAddPrintersActivityName())) {
continue;
}
+ ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo;
ComponentName addPrintersComponentName = new ComponentName(
- resolveInfo.serviceInfo.packageName,
- addPrintersActivity);
- Intent addPritnersIntent = new Intent(Intent.ACTION_MAIN)
+ serviceInfo.packageName, enabledService.getAddPrintersActivityName());
+ Intent addPritnersIntent = new Intent()
.setComponent(addPrintersComponentName);
// The add printers activity is valid - add it.
- if (!getActivity().getPackageManager().queryIntentActivities(
- addPritnersIntent, 0).isEmpty()) {
- mAddPrinterServices.add(printServiceInfo);
+ PackageManager pm = getActivity().getPackageManager();
+ List<ResolveInfo> resolvedActivities = pm.queryIntentActivities(addPritnersIntent, 0);
+ if (!resolvedActivities.isEmpty()) {
+ // The activity is a component name, therefore it is one or none.
+ ActivityInfo activityInfo = resolvedActivities.get(0).activityInfo;
+ if (activityInfo.exported
+ && (activityInfo.permission == null
+ || pm.checkPermission(activityInfo.permission,
+ getActivity().getPackageName())
+ == PackageManager.PERMISSION_GRANTED)) {
+ mAddPrinterServices.add(enabledService);
+ }
}
}
}
@@ -228,7 +241,11 @@
printService.getAddPrintersActivityName());
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(componentName);
- startActivity(intent);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException anfe) {
+ Log.w(LOG_TAG, "Couldn't start settings activity", anfe);
+ }
}
});
@@ -238,7 +255,11 @@
builder.setPositiveButton(R.string.search_play_store,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
- startActivity(marketIntent);
+ try {
+ startActivity(marketIntent);
+ } catch (ActivityNotFoundException anfe) {
+ Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
+ }
}
});
}
diff --git a/packages/SettingsProvider/res/values-en-rIN/strings.xml b/packages/SettingsProvider/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..c19fdd7
--- /dev/null
+++ b/packages/SettingsProvider/res/values-en-rIN/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">"Settings Storage"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-et-rEE/strings.xml b/packages/SettingsProvider/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..30b7293
--- /dev/null
+++ b/packages/SettingsProvider/res/values-et-rEE/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">"Seadete talletusruum"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-fr-rCA/strings.xml b/packages/SettingsProvider/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..c90eb09
--- /dev/null
+++ b/packages/SettingsProvider/res/values-fr-rCA/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">"Stockage des paramètres"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-hy-rAM/strings.xml b/packages/SettingsProvider/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..b1f1afb
--- /dev/null
+++ b/packages/SettingsProvider/res/values-hy-rAM/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">"Կարգավորումների պահուստ"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ka-rGE/strings.xml b/packages/SettingsProvider/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..691a2e9
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ka-rGE/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">"პარამეტრების საცავი"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-km-rKH/strings.xml b/packages/SettingsProvider/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..7be6242
--- /dev/null
+++ b/packages/SettingsProvider/res/values-km-rKH/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">"កំណត់ការផ្ទុក"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-lo-rLA/strings.xml b/packages/SettingsProvider/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..4e57936
--- /dev/null
+++ b/packages/SettingsProvider/res/values-lo-rLA/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">"ບ່ອນເກັບຂໍ້ມູນການຕັ້ງຄ່າ"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-mn-rMN/strings.xml b/packages/SettingsProvider/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..9452145
--- /dev/null
+++ b/packages/SettingsProvider/res/values-mn-rMN/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">"Тохиргооны Сан"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ms-rMY/strings.xml b/packages/SettingsProvider/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..9108b07
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ms-rMY/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">"Storan Tetapan"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-zh-rHK/strings.xml b/packages/SettingsProvider/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..977c9b9
--- /dev/null
+++ b/packages/SettingsProvider/res/values-zh-rHK/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">"設定儲存空間"</string>
+</resources>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index effdcb9..577f69c 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -19,6 +19,6 @@
<string name="app_label" msgid="3701846017049540910">"Prostředí"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Byla vytvořena zpráva o chybě"</string>
<string name="bugreport_finished_text" msgid="3559904746859400732">"Zprávu o chybě můžete sdílet klepnutím."</string>
- <string name="bugreport_confirm" msgid="5130698467795669780">"Zprávy o chybách obsahují data z různých souborů protokolů systému včetně osobních a soukromých informací. Zprávy o chybách sdílejte pouze s aplikacemi a uživateli, kterým důvěřujete."</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Chybová hlášení obsahují data z různých souborů protokolů systému včetně osobních a soukromých informací. Chybová hlášení sdílejte pouze s aplikacemi a uživateli, kterým důvěřujete."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobrazit tuto zprávu příště"</string>
</resources>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..68708e0
--- /dev/null
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -0,0 +1,24 @@
+<?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_finished_title" msgid="2293711546892863898">"Bug report captured"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Touch to share your bug report"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
+</resources>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..7788158
--- /dev/null
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -0,0 +1,24 @@
+<?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">"Kest"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Veaaruanne jäädvustati"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Veaaruande jagamiseks puudutage"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Veaaruanded sisaldavad andmeid erinevatest süsteemi logifailidest, sh isiklikku ja privaatset teavet. Jagage veaaruandeid ainult usaldusväärsete rakenduste ja inimestega."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Kuva see sõnum järgmisel korral"</string>
+</resources>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..c672f23
--- /dev/null
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -0,0 +1,24 @@
+<?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_finished_title" msgid="2293711546892863898">"Rapport de bogue enregistré"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Appuyer ici pour partager votre rapport de bogue"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bogue contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bogue qu\'avec les applications et les personnes que vous estimez fiables."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
+</resources>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index 4ea0664..7e73c79 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -19,6 +19,6 @@
<string name="app_label" msgid="3701846017049540910">"शेल"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"बग रिपोर्ट कैप्चर कर ली गई"</string>
<string name="bugreport_finished_text" msgid="3559904746859400732">"अपनी बग रिपोर्ट साझा करने के लिए स्पर्श करें"</string>
- <string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्ट में व्यक्तिगत और निजी जानकारी सहित, सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा होता है. बग रिपोर्ट केवल विश्वसनीय एप्लिकेशन और व्यक्तियों से ही साझा करें."</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्ट में व्यक्तिगत और निजी जानकारी सहित, सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा होता है. बग रिपोर्ट केवल विश्वसनीय एप्स और व्यक्तियों से ही साझा करें."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यह संदेश अगली बार दिखाएं"</string>
</resources>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..ea7fa9f
--- /dev/null
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -0,0 +1,24 @@
+<?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">"Խեցի"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Վրիպակի զեկույց ստացվեց"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Հպեք` ձեր վրիպակի մասին զեկույցը տարածելու համար"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Վրիպակի զեկույցները պարունակում են տվյալներ համակարգի տարբեր մուտքի ֆայլերից, այդ թվում նաև անհատական և գաղտնի տեղեկություններ: Վրիպակի զեկույցները կիսեք միայն այն հավելվածների և մարդկանց հետ, որոնց վստահում եք:"</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Այս հաղորդագրությունը ցույց տալ հաջորդ անգամ"</string>
+</resources>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..7d9c72a
--- /dev/null
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -0,0 +1,24 @@
+<?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">"გარეკანი"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"ანგარიში ხარვეზების შესახებ შექმნილია"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"შეეხეთ თქვენი ხარვეზების ანგარიშის გასაზიარებლად"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"ხარვეზის ანგარიშები მოიცავს მონაცემებს სხვადასხვა სისტემური ჟურნალის ფაილებიდან, მათ შორის პირად და კონფიდენციალურ ინფორმაციას."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"შემდგომში აჩვენე ეს შეტყობინება"</string>
+</resources>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..efb345c
--- /dev/null
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -0,0 +1,24 @@
+<?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">"សែល"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"បានចាប់យករបាយការណ៍កំហុស"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"ប៉ះ ដើម្បីចែករំលែករបាយការណ៍កំហុសរបស់អ្នក"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"របាយការណ៍កំហុសរួមមានឯកសារកំណត់ហេតុផ្សេងៗរបស់ប្រព័ន្ធ រួមមានព័ត៌មានផ្ទាល់ខ្លួន និងឯកជន។ ចែករំលែករបាយការណ៍កំហុសជាមួយកម្មវិធី និងមនុស្សដែលអ្នកទុកចិត្ត។"</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"បង្ហាញសារនេះពេលក្រោយ"</string>
+</resources>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..a237d48
--- /dev/null
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -0,0 +1,24 @@
+<?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_finished_title" msgid="2293711546892863898">"ລາຍງານຈຸດບົກພ່ອງຖືກເກັບກຳແລ້ວ"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"ແຕະເພື່ອສົ່ງການລາຍງານປັນຫາຂອງທ່ານ"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"ການລາຍງານຂໍ້ຜິດພາດປະກອບມີ ຂໍ້ມູນຈາກໄຟລ໌ບັນທຶກຂອງລະບົບຫຼາຍໄຟລ໌, ຮວມທັງຂໍ້ມູນສ່ວນໂຕນຳ. ທ່ານຕ້ອງແບ່ງປັນລາຍງານຂໍ້ຜິດພາດໃຫ້ແອັບຯ ແລະຄົນທີ່ທ່ານເຊື່ອຖືໄດ້ເທົ່ານັ້ນ."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ສະແດງຂໍ້ຄວາມນີ້ອີກໃນເທື່ອຕໍ່ໄປ"</string>
+</resources>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..f74298d
--- /dev/null
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -0,0 +1,24 @@
+<?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">"Шел"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Алдааны мэдээлэл хүлээн авав"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Та алдааны мэдэгдлийг хуваалцах бол хүрнэ үү"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Алдааны репорт нь хувийн болон нууц мэдээлэл зэргийг агуулсан системийн төрөл бүрийн лог файлын датаг агуулна. Алдааны репортыг зөвхөн итгэлтэй апп болон хүмүүст хуваалцана уу."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Энэ мессежийг дараагийн удаа харуулах"</string>
+</resources>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..8d1e4a2
--- /dev/null
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -0,0 +1,24 @@
+<?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_finished_title" msgid="2293711546892863898">"Laporan pepijat telah ditangkap"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Sentuh untuk berkongsi laporan pepijat anda"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Laporan pepijat mengandungi data dari pelbagai fail log sistem, termasuk maklumat peribadi dan sulit. Kongsikan laporan pepijat hanya dengan apl dan orang yang anda percayai."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tunjukkan mesej ini pada masa akan datang"</string>
+</resources>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..b5f1935
--- /dev/null
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -0,0 +1,24 @@
+<?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">"命令介面"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告中有來自系統各個記錄檔案的資料,包括個人和私人資料。請只與您信任的應用程式和用戶分享錯誤報告。"</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再顯示這則訊息"</string>
+</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 5e198a2..fa5c769 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -189,6 +189,35 @@
android:taskAffinity="com.android.systemui.net"
android:excludeFromRecents="true" />
+ <!-- platform logo easter egg activity -->
+ <activity
+ android:name=".DessertCase"
+ android:exported="true"
+ android:label="@string/dessert_case"
+ android:theme="@android:style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+ android:hardwareAccelerated="true"
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="com.android.internal.category.PLATLOGO" />
+ </intent-filter>
+ </activity>
+
+ <!-- a gallery of delicious treats -->
+ <service
+ android:name=".DessertCaseDream"
+ android:exported="true"
+ android:label="@string/dessert_case"
+ android:enabled="false"
+ >
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
+
<activity android:name=".Somnambulator"
android:label="@string/start_dreams"
android:icon="@mipmap/ic_launcher_dreams"
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
index 8907055..873ca7e 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
index 02fd1043..288d36a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
index 8966a10..3f7c4b0 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
index 950b136..956bb7c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
index 2abd625..a53aef1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
index d79612a..e1b2145 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
index 7a84631..2d8f81d 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
index 4be4846..61c6d11 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
index d8fac96..90eece6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
index 1024af9..382cf23 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
index 3db8fde..a4b3b37 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
index 8e797e1..ee5f623 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
index f6fc8cc..3d21350 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 7bf7104..40fbaec 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
index d295762..61b4569 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
index 9f47cc0..1a0312b 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
index b680ddb..8715a11 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
index f969d05..487a0b1 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
index 457be69..225d924 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
index d232bf4..37d17d2 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
index 6a9e91d3..3361e34 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
index 4174a04..b380327 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
index 7928440..0ec4d23 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
index 878bead..e55f2bf 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
index 18d10c7..8aa6e3a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
index 3baf867..bf68b22 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
index c78258a..7e96395e 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 5c15315..382ef39 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
index 4c40ff2..a2bb50a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
index 337a347b..aaeeb1b 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
index 03aa648..79cfcee 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
index f9ba76f..c3bfcfb 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 28128da..a1a2ee5 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan dalk gemonitor word"</string>
- <string name="done_button" msgid="1759387181766603361">"Klaar"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Netwerkmonitering"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Hierdie toestel word bestuur deur: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nJou administrateur kan jou netwerkaktiwiteit monitor, insluitend e-pos, programme en veilige webwerwe.\n\nKontak jou administrateur vir meer inligting."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"\'n Derdeparty kan jou netwerk\n-aktiwiteit monitor, insluitend e-pos, programme en veilige webwerwe.\n\n\'n Vertroude eiebewys wat op jou toestel geïnstalleer is, maak dit moontlik."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Gaan vertroude eiebewyse na"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 40479b5..f56d200 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ብሩህነት"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"አውታረ መረብ በክትትል ውስጥ ሊሆን ይችላል"</string>
- <string name="done_button" msgid="1759387181766603361">"ተከናውኗል"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"የአውታረ መረብ ክትትል"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"መሳሪያው የሚተዳደረው፦ በ<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>። \n\nአስተዳዳሪዎ ኢሜይሎችዎን፣ መተግበሪያዎችዎን እና ደህንነታቸው አስተማማኝ የሆኑ ድር ጣቢያዎችን ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ይችላል።\n\nለተጨማሪ መረጃ አስተዳዳሪዎን ያግኙ።"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"ሶስተኛ ወገን ኢሜይሎችዎን፣ መተግበሪያዎችዎን እና ደህንነታቸው አስተማማኝ የሆኑ\nድር ጣቢያዎችን ጨምሮ አውታረ መረብ እንቅስቃሴዎን መከታተል ይችላል።\n\nበመሳሪያዎ ላይ የተጫነ የታመነ ምስክርነት ይህን የሚቻል አድርጎታል።"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"የታመኑ ምስክርነቶችን ይፈትሹ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 93a9164..3c709e4 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"السطوع"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"قد تكون الشبكة مراقبة"</string>
- <string name="done_button" msgid="1759387181766603361">"تم"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"مراقبة الشبكات"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"هذا الجهاز يديره: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nيستطيع مشرفك مراقبة أنشطة الشبكة بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب الآمنة.\n\nللمزيد من المعلومات، اتصل بالمشرف."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"بإمكان الطرف الثالث مراقبة أنشطة\nالشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب الآمنة.\n\nوتجعل بيانات الاعتماد الموثوق فيها والمثبتة على جهازك حدوث هذا ممكنًا."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"التحقق من بيانات الاعتماد الموثوق فيها"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index eb455c1..b379bab 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -204,14 +204,4 @@
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string>
<!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
<skip />
- <!-- no translation found for done_button (1759387181766603361) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_dialog_title (1273796967092027291) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_info_message (5430320539555358452) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_warning_message (2033091656129963669) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_settings_button (7946956977377166709) -->
- <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e839143..5d2f249 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркост"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежата може да се наблюдава"</string>
- <string name="done_button" msgid="1759387181766603361">"Готово"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Наблюдение на мрежата"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Това устройство се управлява от: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nАдминистраторът ви може да наблюдава активността ви в мрежата, включително имейлите, приложенията и сигурните уебсайтове.\n\nЗа повече информация се свържете с него."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Трета страна може да наблюдава активността ви в\nмрежата, включително имейлите, приложенията и сигурните уебсайтове.\n\nТова е възможно благодарение на инсталирани на устройството ви надеждни идентификационни данни."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Проверка на надеждните идентификационни данни"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index f3b7714..e0ed9fb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillantor"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Pot ser que la xarxa se supervisi."</string>
- <string name="done_button" msgid="1759387181766603361">"Fet"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Supervisió de xarxes"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> administra aquest dispositiu.\n\nEl teu administrador té capacitat per supervisar la teva activitat de xarxa, inclosos els correus electrònics, les aplicacions i els llocs web segurs.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Un tercer té la capacitat per supervisar la teva activitat de\nxarxa, inclosos els correus electrònics, les aplicacions i els llocs web segurs.\n\nHi ha una credencial de confiança instal·lada que fa que això sigui possible."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Comprova les credencials de confiança"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5977c35..0b0597a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Síť může být monitorována"</string>
- <string name="done_button" msgid="1759387181766603361">"Hotovo"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorování sítě"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Toto zařízení je spravováno doménou <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nSprávce může monitorovat aktivitu v síti, včetně e-mailů, aplikací a zabezpečených webů.\n\nChcete-li získat další informace, kontaktujte svého správce."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Vaše aktivita v síti, včetně e-mailů, aplikací a zabezpečených\nwebových stránek může být monitorována třetí stranou.\n\nUmožňují to důvěryhodné identifikační údaje nainstalované ve vašem zařízení."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Zkontrolovat důvěryhodné identifikační údaje"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 08c42d0..e502b26 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netværket kan være overvåget"</string>
- <string name="done_button" msgid="1759387181766603361">"Udfør"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Overvågning af netværk"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Denne enhed er administreret af: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nDin administrator kan overvåge dine netværksaktiviteter, f.eks. e-mails, apps og sikre websites.\n\nFå flere oplysninger ved at kontakte din administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"En tredjepart kan overvåge dine netværksaktiviteter, \nf.eks.e-mails, apps og sikre websites.\n\nBetroede loginoplysninger, der er installeret på din enhed, gør dette muligt."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Kontrollér betroede loginoplysninger"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 8b52a11..17b425b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helligkeit"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Das Netzwerk wird möglicherweise überwacht."</string>
- <string name="done_button" msgid="1759387181766603361">"Fertig"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Netzwerküberwachung"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Dieses Gerät wird von <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> verwaltet.\n\nIhr Administrator kann Ihre Netzwerkaktivitäten überwachen, einschließlich E-Mails, Apps und sicheren Websites.\n\nWenden Sie sich für weitere Informationen an Ihren Administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Dritte können Ihre Netzwerkaktivitäten\nüberwachen, einschließlich E-Mails, Apps und sicheren Websites.\n\nDies wird durch vertrauenswürdige Anmeldedaten ermöglicht, die auf Ihrem Gerät installiert sind."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Vertrauenswürdige Anmeldedaten überprüfen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c437eb6..43b9cbc 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Φωτεινότητα"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
- <string name="done_button" msgid="1759387181766603361">"Τέλος"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Παρακολούθηση δικτύου"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Η συσκευή αυτή διαχειρίζεται από: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nΟ διαχειριστής σας έχει τη δυνατότητα παρακολούθησης της δραστηριότητας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ασφαλών ιστότοπων.\n\nΓια περισσότερες πληροφορίες επικοινωνήστε με το διαχειριστή σας."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Ένα τρίτο μέρος έχει δυνατότητα παρακολούθησης της δραστηριότητας\nδικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ασφαλών ιστότοπων.\n\nΈνα αξιόπιστο διαπιστευτήριο που έχει εγκατασταθεί στη συσκευή σας επιτρέπει κάτι τέτοιο."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Ελέγξτε τα αξιόπιστα διαπιστευτήρια"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 5255c44..8a16d7c 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
- <string name="done_button" msgid="1759387181766603361">"Finished"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Network Monitoring"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"This device is managed by: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"A third party is capable of monitoring your network\nactivity, including emails, apps and secure websites.\n\nA trusted credential installed on your device is making this possible."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Check trusted credentials"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 5255c44..8a16d7c 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
- <string name="done_button" msgid="1759387181766603361">"Finished"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Network Monitoring"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"This device is managed by: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"A third party is capable of monitoring your network\nactivity, including emails, apps and secure websites.\n\nA trusted credential installed on your device is making this possible."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Check trusted credentials"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f5b2df7..1aed7dc 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada."</string>
- <string name="done_button" msgid="1759387181766603361">"Listo"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Supervisión de red"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Este dispositivo es administrado por: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nEl administrador puede supervisar la actividad de la red, incluidos los mensajes de correo electrónico, las aplicaciones y los sitios web seguros.\n\nPara obtener más información, comunícate con el administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Un tercero puede supervisar la actividad de la red,\nincluidos los mensajes de correo electrónico, las aplicaciones y los sitios web seguros.\n\nEsto es posible debido a que hay una credencial de confianza instalada en el dispositivo."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Comprobar credenciales de confianza"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b81b487..5386842 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada"</string>
- <string name="done_button" msgid="1759387181766603361">"Listo"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Supervisión de red"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Este dispositivo está administrado por: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nTu administrador puede supervisar la actividad de la red, incluidos los mensajes de correo electrónico, las aplicaciones y los sitios web seguros.\n\nPara obtener más información, ponte en contacto con tu administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Un tercero puede supervisar la actividad de la\nred, incluidos los mensajes de correo electrónico, las aplicaciones y los sitios web seguros.\n\nEsto es posible por una credencial de confianza instalada en tu dispositivo."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Comprobar credenciales de confianza"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 69da334..335feaa 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Heledus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAATNE"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Võrku võidakse jälgida"</string>
- <string name="done_button" msgid="1759387181766603361">"Valmis"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Võrgu jälgimine"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Seadet haldab: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVõrguadministraator saab jälgida teie võrgutoiminguid, sh meile, rakendusi ja turvalisi veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Kolmas osapool saab jälgida teie\nvõrgutoiminguid, sh meile, rakendusi ja turvalisi veebisaite.\n\nSeda võimaldab teie seadmesse installitud usaldusväärne mandaat."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Kontrolli usaldusväärseid mandaate"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 412e749..489b654 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"روشنایی"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ممکن است شبکه نظارت شده باشد"</string>
- <string name="done_button" msgid="1759387181766603361">"انجام شد"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"پایش شبکه"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"این دستگاه توسط: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> مدیریت میشود.\n\nسرپرست شما میتواند فعالیتتان را در شبکه نظارت کند، از جمله ایمیلها، برنامهها، و وبسایتهای ایمن.\n\nبرای کسب اطلاعات بیشتر، با سرپرستتان تماس بگیرید."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"یک شخص ثالث قادر به نظارت بر فعالیت\nشبکه شما، از جمله ایمیلها، برنامهها، و وبسایتهای ایمن است.\n\nیک اعتبارنامه قابل اعتماد نصب شده بر روی دستگاهتان این کار را امکانپذیر میکند."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"بررسی اعتبارنامههای قابل اعتماد"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index dbd228e..852ec08 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kirkkaus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Verkkoa saatetaan valvoa"</string>
- <string name="done_button" msgid="1759387181766603361">"Valmis"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Verkon valvonta"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Tämän laitteen hallinnoija: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nJärjestelmänvalvoja pystyy valvomaan toimiasi verkossa, esimerkiksi sähköpostin, sovellusten ja turvallisten verkkosivustojen käyttöä.\n\nSaat lisätietoja järjestelmänvalvojalta."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Kolmas osapuoli pystyy valvomaan toimiasi verkossa,\n esimerkiksi sähköpostin, sovellusten ja turvallisten verkkosivustojen käyttöä.\n\nLaitteeseesi asennetut luotetut käyttöoikeustiedot tekevät tämän mahdolliseksi."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Tarkista luotetut käyttöoikeustiedot"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 6071659..48f62d3 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Le réseau peut être surveillé"</string>
- <string name="done_button" msgid="1759387181766603361">"Terminé"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Surveillance réseau"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Cet appareil est géré par : <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVotre administrateur est en mesure de surveiller l\'activité de votre réseau, y compris les courriels, les applications et les sites Web sécurisés.\n\nPour obtenir plus d\'information à ce sujet, communiquez avec votre administrateur."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Un tiers peut surveiller votre activité réseau,\n y compris les courriels, les applications et les sites Web sécurisés.\n\nUn certificat de confiance installé sur votre appareil rend cela possible."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Vérifier les certificats de confiance"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4982ed3..2af370b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Il est possible que le réseau soit surveillé."</string>
- <string name="done_button" msgid="1759387181766603361">"OK"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Surveillance du réseau"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Cet appareil est géré par <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVotre administrateur a la possibilité de surveiller votre activité sur le réseau, y compris les e-mails, les applications et les sites Web sécurisés.\n\nPour en savoir plus, veuillez contacter votre administrateur."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Il est possible qu\'un tiers surveille votre activité sur le réseau,\ny compris les e-mails, les applications et les sites Web sécurisés.\n\nCela est dû à la présence d\'un certificat de confiance installé sur votre appareil."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Vérifier les certificats de confiance"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 4c3c87f..5256ff0 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"चमक"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
- <string name="done_button" msgid="1759387181766603361">"पूर्ण"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"नेटवर्क मॉनिटरिंग"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"यह उपकरण <xliff:g id="MANAGING_DOMAIN">%s</xliff:g> के द्वारा प्रबंधित किया जाता है.\n\nआपका व्यवस्थापक आपकी नेटवर्क गतिविधि को, साथ ही ईमेल, एप्स, और सुरक्षित वेबसाइटों को मॉनिटर करने में सक्षम है.\n\nअधिक जानकारी के लिए, अपने व्यवस्थापक से संपर्क करें."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"एक तृतीय पक्ष आपकी नेटवर्क\nगतिविधि को, साथ ही ईमेल, एप्स, और सुरक्षित वेबसाइटों को मॉनिटर करने में सक्षम है.\n\nआपके उपकरण पर इंस्टॉल किए गए एक विश्वसनीय क्रेडेंशियल के कारण ऐसा हो रहा है."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"विश्वसनीय क्रेडेंशियल की जांच करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 92e1b21..84d4111 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svjetlina"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKI"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadzire"</string>
- <string name="done_button" msgid="1759387181766603361">"Završeno"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Nadzor mreže"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Ovim uređajem upravlja: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVaš administrator može nadzirati vašu mrežnu aktivnost, uključujući e-poštu, aplikacije i sigurne web-lokacije.\n\nza više informacija kontaktirajte svojeg administratora."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Treća strana može nadzirati vaše mrežne\naktivnosti, uključujući e-poštu, aplikacije i sigurne web-lokacije.\n\nTo omogućuje pouzdana vjerodajnica instalirana na vašem uređaju."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Provjeri pouzdane vjerodajnice"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ad9c7b7..55a135f 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Fényerő"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"automatikus"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Lehet, hogy a hálózat felügyelt"</string>
- <string name="done_button" msgid="1759387181766603361">"Kész"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Hálózatfelügyelet"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Az eszköz kezelője: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nRendszergazdája képes az Ön hálózati tevékenységének, köztük az e-maileknek, az alkalmazásoknak és a biztonságos webhelyeknek a megfigyelésére.\n\nTovábbi információért forduljon rendszergazdájához."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Egy harmadik fél képes az Ön hálózati\ntevékenységének a megfigyelésére, beleértve az e-maileket, alkalmazásokat és biztonságos webhelyeket.\n\nEgy, az eszközre telepített megbízható tanúsítvány teszi ezt lehetővé."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Megbízható tanúsítványok ellenőrzése"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 06b897a..ce97d01 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Պայծառություն"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Ինքնաշխատ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ցանցը կարող է վերահսկվել"</string>
- <string name="done_button" msgid="1759387181766603361">"Պատրաստ է"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Ցանցի մշտադիտարկում"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Այս սարքը կառավարվում է <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>-ի կողմից:\n\nՁեր կառավարիչն ի վիճակի է մշտադիտարկել ձեր ցանցային գործունեությունը, այդ թվում՝ նամակները, հավելվածները և անվտանգ կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ձեր կառավարչին:"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Երրորդ կողմն ի վիճակի է վերահսկել ձեր ցանցային\nգործունեությունը, այդ թվում՝ նամակները, հավելվածները և անվտանգ կայքերը:\n\nՁեր սարքում տեղադրված վստահելի վկայագրերը տալիս են դրա հնարավորությունը:"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Ստուգել վստահելի վկայագրերը"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3af3a34..6589ae1 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Jaringan mungkin dipantau"</string>
- <string name="done_button" msgid="1759387181766603361">"Selesai"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Pemantauan Jaringan"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Perangkat ini dikelola oleh: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministrator Anda dapat memantau aktivitas jaringan Anda, termasuk email, aplikasi, dan situs web aman.\n\nUntuk informasi selengkapnya, hubungi administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Pihak ketiga dapat memantau aktivitas\njaringan Anda, termasuk email, aplikasi, dan situs web aman.\n\nKredensial tepercaya yang terpasang di perangkat Anda membuatnya dapat dilakukan."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Periksa kredensial tepercaya"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index d936e5f..2aaa1e7 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosità"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"La rete potrebbe essere monitorata"</string>
- <string name="done_button" msgid="1759387181766603361">"Fine"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitoraggio rete"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Questo dispositivo è gestito da: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nIl tuo amministratore è in grado di monitorare l\'attività della rete, inclusi siti web sicuri, email e app.\n\nPer ulteriori informazioni, contatta il tuo amministratore."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Una terza parte è in grado di monitorare l\'attività della\nrete, inclusi siti web sicuri, email e app.\n\nCiò è reso possibile da una credenziale attendibile installata sul dispositivo."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Verifica credenziali attendibili"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3b5080e..668c77a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"בהירות"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ייתכן שהרשת מנוטרת"</string>
- <string name="done_button" msgid="1759387181766603361">"בוצע"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ניטור רשתות"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"המכשיר הזה מנוהל על ידי: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nמנהל המערכת שלך יכול לנטר את הפעילות ברשת, כולל דוא\"ל, אפליקציות ואתרים מאובטחים.\n\nלמידע נוסף, צור קשר עם מנהל המערכת שלך."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"צד שלישי יכול לנטר את הפעילות שלך\nברשת, כולל דוא\"ל, אפליקציות ואתרים מאובטחים.\n\nפרטי כניסה מהימנים המותקנים במכשיר שלך מאפשרים זאת."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"בדוק פרטי כניסה מהימנים"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index f42dd16..0451117 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"画面の明るさ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ネットワークが監視される場合があります"</string>
- <string name="done_button" msgid="1759387181766603361">"完了"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ネットワーク監視"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"この端末は<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>によって管理されています。\n\n管理者はあなたのネットワークアクティビティ(メール、アプリ、保護されたウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"第三者があなたのネットワーク\nアクティビティ(メール、アプリ、保護されたウェブサイトなど)を監視できます。\n\nこれは、信頼できる認証情報が端末にインストールされているためです。"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"信頼できる認証情報を確認"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index b9963d5..49ed9ba 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"განათება"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ავტომატურად"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"შესაძლოა ქსელი მონიტორინგის ქვეშ იმყოფება"</string>
- <string name="done_button" msgid="1759387181766603361">"დასრულდა"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ქსელის მონიტორინგი"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"თქვენ მოწყობილობის მმართველი არის: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nთქვენს ადმინისტრატოს შეუძლია განახორციელოს თქვენი ქსელის აქტივობის მონიტორინგი, მათ შორის ელფოსტების, აპების და უსაფრთხო ვებსაიტების მონიტორინგი.\n\nდამატებითი ინფორმაციისათვის, დაუკავშირდით ადმინისტრატორს."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"მესამე მხარეს შეუძლია განახორციელოდს თქვენი ქსელის \nაქტივობა, მათ შორის ელფოსტები, აპები და უსაფრთხო ვებსაიტები.\n\nეს შესაძლებელია თქვენს მოწყობილობაზე დაყენებული სანდო ავთენტიკაციის მონაცემების საშუალებით."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"სანდო ავთენტიკაციის მონაცემების შემოწმება"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 211c286..5e0318d 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ពន្លឺ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ស្វ័យប្រវត្តិ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"បណ្ដាញអាចត្រូវបានតាមដាន"</string>
- <string name="done_button" msgid="1759387181766603361">"រួចរាល់"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ការពិនិត្យបណ្ដាញ"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"ឧបករណ៍នេះត្រូវបានគ្រប់គ្រងដោយ៖ <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>។\n\nអ្នកគ្រប់គ្រងរបស់អ្នកអាចពិនិត្យសកម្មភាពបណ្ដាញរបស់អ្នករួមមាន អ៊ីមែល, កម្មវិធី និងតំបន់បណ្ដាញមានសុវត្ថិភាព។\n\nចំពោះព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក។"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"ភាគីទីបីអាចពិនិត្យសកម្មភាព \n បណ្ដាញរបស់អ្នករួមមាន អ៊ីមែល, កម្មវិធី និងសុវត្ថិភាពតំបន់បណ្ដាញ។\n\n ព័ត៌មានដែលទុកចិត្តបានដំឡើងក្នុងឧបករណ៍របស់អ្នកអាចធ្វើការងារនេះបាន។"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"ពិនិត្យព័ត៌មានសម្ងាត់ដែលទុកចិត្ត"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 3b37888..7711bd5 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"밝기"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"네트워크가 모니터링될 수 있음"</string>
- <string name="done_button" msgid="1759387181766603361">"완료"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"네트워크 모니터링"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"이 기기는 <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>에서 관리합니다.\n\n관리자는 이메일, 앱 및 보안 웹사이트를 포함한 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 정보는 관리자에게 문의하세요."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">\n\n"기기에 신뢰할 수 있는 자격증명이 설치되어있기 때문에 제3자가 이메일, 앱 및 보안 웹사이트를 포함한 네트워크\n활동을 모니터링할 수 있습니다."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"신뢰할 수 있는 자격증명 확인"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 968fee4..e62c4f3 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ຄວາມແຈ້ງ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ອັດຕະໂນມັດ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ການນຳໃຊ້ເຄືອຂ່າຍອາດມີການກວດສອບຕິດຕາມ"</string>
- <string name="done_button" msgid="1759387181766603361">"ແລ້ວໆ"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"ການກວດສອບຕິດຕາມເຄືອຂ່າຍ"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"ອຸປະກອນນີ້ຈັດການໂດຍ: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນຂອງທ່ານ ສາມາດກວດສອບຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານໄດ້ ຮວມທັງ: ອີເມວ, ແອັບຯ ແລະເວັບໄຊທີ່ເຂົ້າລະຫັດຕ່າງໆ.\n\nສຳລັບຂໍ້ມູນເພີ່ມເຕີມ, ໃຫ້ຕິດຕໍ່ຜູ່ເບິ່ງແຍງລະບົບຂອງທ່ານ."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"ບຸກຄົນທີສາມສາມາດກວດສອບຕິດຕາມເຄືອຂ່າຍຂອງທ່ານ\nຮວມທັງ: ອີເມວ, ແອັບຯ ແລະເວັບໄຊທີ່ເຂົ້າລະຫັດຕ່າງໆ.\n\nຂໍ້ມູນພິສູດຢືນຢັນທີ່ເຊື່ອຖືໄດ້ທີ່ມີຕິດຕັ້ງໃນອຸປະກອນຂອງທ່ານ ເຮັດໃຫ້ຂັ້ນຕອນນີ້ດຳເນີນໄປໄດ້."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"ກວດສອບການພິສູດຢືນຢັນທີ່ເຊື່ອຖືໄດ້"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index b0693d5..173fbbf 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Skaistis"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Tinklas gali būti stebimas"</string>
- <string name="done_button" msgid="1759387181766603361">"Atlikta"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Tinklo stebėjimas"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Šį įrenginį tvarko <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministratorius gali stebėti jūsų tinklo veiklą, įskaitant el. paštą, programas ir saugias svetaines.\n\nJei norite gauti daugiau informacijos, susisiekite su administratoriumi."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Trečioji šalis gali stebėti jūsų tinklo\nveiklą, įskaitant el. paštą, programas ir saugias svetaines.\n\nVisa tai įmanoma dėl jūsų įrenginyje įdiegtų patikimų prisijungimo duomenų."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Tikrinti patikimus prisijungimo duomenis"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b18bd6c..bdb8975 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Spilgtums"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMĀTISKI"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
- <string name="done_button" msgid="1759387181766603361">"Gatavs"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Tīkla pārraudzība"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Šo ierīci pārvalda domēns <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nJūsu administrators var pārraudzīt darbības, ko veicat tīklā, tostarp e-pasta ziņojumus, lietotnes un drošās vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar savu administratoru."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Trešā puse var pārraudzīt darbības, ko veicat tīklā,\ntostarp e-pasta ziņojumus, lietotnes un drošās vietnes.\n\nTas ir iespējams, jo jūsu ierīcē ir instalēti uzticami akreditācijas dati."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Pārbaudīt uzticamos akreditācijas datus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index e5d2af3..6a548db 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Тодрол"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОМАТ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Сүлжээ хянагдаж байж болзошгүй"</string>
- <string name="done_button" msgid="1759387181766603361">"Дууссан"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Сүлжээний Хяналт"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Энэ төхөөрөмжийг удирдагч: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nТаны админ имэйл, апп-ууд болон аюулгүй вебсайтуудыг оруулан таны сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээллийг өөрийн админтай холбогдож авна уу."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Гуравдагч талын этгээд таны сүлжээг хянаж байж болзошгүй\nүүнд имэйл, апп-ууд болон аюулгүй вебсайтууд багтана.\n\nТаны төхөөрөмж дээр суулгасан итгэмжлэгдсэн жуух энэ боломжоор хангаж байна."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Итгэмжлэгдсэн жуухуудыг шалгах"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 40468f5..bb780fe 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rangkaian mungkin dipantau"</string>
- <string name="done_button" msgid="1759387181766603361">"Selesai"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Pemantauan Rangkaian"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Peranti ini diuruskan oleh: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nPentadbir anda boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web selamat.\n\nUntuk maklumat lanjut, hubungi pentadbir anda."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Pihak ketiga boleh memantau aktiviti \nrangkaian anda, termasuk e-mel, apl dan tapak web selamat.\n\nBukti kelayakan dipercayai yang dipasang pada peranti anda membolehkan perkara ini."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Semak bukti kelayakan dipercayai"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index cd463c8..82c4090 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nettverket blir muligens overvåket"</string>
- <string name="done_button" msgid="1759387181766603361">"Fullført"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Nettverksovervåking"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Denne enheten administreres av: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministratoren din kan overvåke nettverksaktiviteten din, inkludert e-post, apper og sikre nettsteder.\n\nFor mer informasjon kan du kontakte administratoren din."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"En tredjepart kan overvåke nettverksaktiviteten din\n, inkludert e-poster, apper og sikre nettsteder.\n\nEn installering av pålitelig legitimasjon gjør dette mulig."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Sjekk pålitelig legitimasjon"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 0996392..46b14a4 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan worden gecontroleerd"</string>
- <string name="done_button" msgid="1759387181766603361">"Gereed"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Netwerkcontrole"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Dit apparaat wordt beheerd door: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nUw beheerder kan uw netwerkactiviteit controleren, waaronder e-mails, apps en beveiligde websites.\n\nNeem contact op met uw beheerder voor meer informatie."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Een derde partij kan uw netwerkactiviteit\ncontroleren, waaronder e-mails, apps en beveiligde websites.\n\nDit wordt mogelijk gemaakt door vertrouwde inloggegevens die zijn geïnstalleerd op uw apparaat."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Vertrouwde inloggegevens controleren"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c3476e5..22bb708 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jasność"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieć może być monitorowana"</string>
- <string name="done_button" msgid="1759387181766603361">"Gotowe"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorowanie sieci"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"To urządzenie jest zarządzane w domenie <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministrator może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i bezpieczne witryny.\n\nWięcej informacji uzyskasz od administratora."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Firma zewnętrzna może monitorować Twoją aktywność w sieci,\nw tym e-maile, aplikacje i bezpieczne witryny.\n\nPozwalają na to zaufane dane uwierzytelniające zainstalowane na tym urządzeniu."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Sprawdź zaufane dane uwierzytelniające"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index dac070f..42b6a62 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorizada"</string>
- <string name="done_button" msgid="1759387181766603361">"Concluído"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorização da Rede"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Este dispositivo é gerido por: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nO seu administrador pode monitorizar a sua atividade de rede, incluindo mensagens de email, aplicações e Websites seguros.\n\nPara obter mais informações, contacte o seu administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"A sua atividade\nde rede, incluindo mensagens de email, aplicações e Websites seguros, pode ser monitorizada por terceiros.\n\nEsta situação é possível graças a uma credencial fidedigna instalada no seu dispositivo."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Verificar credenciais fidedignas"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 711956e..51ce1c6 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorada"</string>
- <string name="done_button" msgid="1759387181766603361">"Concluído"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitoramento de rede"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Este dispositivo é gerenciado por: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nO administrador pode monitorar sua atividade na rede, incluindo e-mails, aplicativos e websites seguros.\n\nPara mais informações, entre em contato com o administrador."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Sua atividade na rede, incluindo e-mails, aplicativos\ne websites seguros, pode ser monitorada por terceiros.\n\nUma credencial confiável instalada no dispositivo permite o monitoramento."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Verificar credenciais confiáveis"</string>
</resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 0a5689c..c26c055 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -366,14 +366,4 @@
<skip />
<!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
<skip />
- <!-- no translation found for done_button (1759387181766603361) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_dialog_title (1273796967092027291) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_info_message (5430320539555358452) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_warning_message (2033091656129963669) -->
- <skip />
- <!-- no translation found for ssl_ca_cert_settings_button (7946956977377166709) -->
- <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 0b93f57..4bd25f8 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminozitate"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rețeaua poate fi monitorizată"</string>
- <string name="done_button" msgid="1759387181766603361">"Terminat"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorizarea rețelei"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Acest dispozitiv este gestionat de: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministratorul este capabil să monitorizeze activitatea dvs. în rețea, inclusiv mesajele e-mail, aplicațiile și site-urile securizate.\n\nPentru mai multe informații, contactați administratorul."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"O terță parte poate monitoriza activitatea dvs. în\nrețea, inclusiv mesajele e-mail, aplicațiile și site-urile securizate.\n\nAcest lucru este posibil deoarece există o acreditare de încredere instalată pe dispozitivul dvs."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Verificați acreditările de încredere"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 2c469b4..0a45aa9 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -202,9 +202,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркость"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Действия в сети могут отслеживаться"</string>
- <string name="done_button" msgid="1759387181766603361">"Готово"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Мониторинг сети"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Устройством управляет администратор домена <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nОн может отслеживать ваши действия в сети, в том числе просматривать письма, приложения и список посещенных веб-сайтов.\n\nЗа дополнительной информацией обратитесь к администратору."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Администратор может отслеживать ваши действия в сети.\nНапример, он может просматривать ваши письма, приложения и список посещенных сайтов.\n\nЭто возможно благодаря надежному сертификату, установленному на устройстве."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Настройки сертификатов"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index d036f0e..8a4ef39 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieť môže byť monitorovaná"</string>
- <string name="done_button" msgid="1759387181766603361">"Hotovo"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Monitorovanie siete"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Toto zariadenie spravuje: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nVáš správca môže monitorovať vašu aktivitu v sieti vrátane e-mailov, aplikácií a zabezpečených webových stránok.\n\nAk chcete získať viac informácií, obráťte sa na svojho správcu."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Tretia strana môže monitorovať vašu aktivitu\nv sieti vrátane e-mailov, aplikácií a zabezpečených webových stránok.\n\nUmožňuje to dôveryhodné poverenie nainštalované vo vašom zariadení."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Skontrolovať dôveryhodné poverenia"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index e0b215a..eaa8b11 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svetlost"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SAMODEJNO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Omrežje je lahko nadzorovano"</string>
- <string name="done_button" msgid="1759387181766603361">"Dokončano"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Nadzor omrežja"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"To napravo upravlja: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nSkrbnik lahko nadzoruje vašo omrežno dejavnost, vključno z e-pošto, aplikacijami in varnimi spletnimi mesti.\n\nZa več informacij se obrnite na skrbnika."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Vašo omrežno dejavnost, vključno z e-pošto, aplikacijami\nin varnimi spletnimi mesti, lahko nadzira tretja oseba.\n\nTo omogoča zaupanja vredna poverilnica, nameščena v vaši napravi."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Preveri zaupanja vredne poverilnice"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 84d72df..ccda6e9 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Осветљеност"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежа се можда надгледа"</string>
- <string name="done_button" msgid="1759387181766603361">"Готово"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Надгледање мреже"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Овим уређајем управља: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nАдминистратор може да надгледа активности на мрежи, укључујући поруке е-поште, апликације и безбедне веб-сајтове.\n\nЗа више информација контактирајте администратора."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Трећа страна може да надгледа активности\nна мрежи, укључујући поруке е-поште, апликације и безбедне веб-сајтове.\n\nТо је могуће захваљујући поузданом акредитиву инсталираном на уређају."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Провери поуздане акредитиве"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d27c9e4..ffe8c84 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ljusstyrka"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nätverket kan vara övervakat"</string>
- <string name="done_button" msgid="1759387181766603361">"Klart"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Nätverksövervakning"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Enheten hanteras av: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nAdministratören kan övervaka dina aktiviteter på nätverket, inklusive e-post, appar och säkra webbplatser.\n\nKontakta din administratör om du vill veta mer."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Dina nätverksaktiviteter kan övervakas av tredje part\n, inklusive e-post, appar och säkra webbplatser.\n\nDetta är möjligt eftersom tillförlitlig autentisering har installerats på enheten."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Kontrollera tillförlitlig autentisering"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index f911f27..bdf22c3 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -196,9 +196,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ung\'avu"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"KIOTOMATIKI"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mtandao unaweza kufuatiliwa"</string>
- <string name="done_button" msgid="1759387181766603361">"Imekamilika"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Ufuatiliaji wa Mtandao"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Kifaa hiki kinasimamiwa na: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nMsimamizi wako anaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu, na tovuti salama.\n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Mtu mwingine anaweza kufuatilia shughuli za mtandao wako\n, ikiwa ni pamoja na barua pepe, programu, na tovuti salama.\n\nKitambulisho cha kuaminika kilichosakinishwa kwenye kifaa chako kinafanikisha hili."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Angalia kitambulisho cha kuaminika"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 2eb8896..af4bb092 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ความสว่าง"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
- <string name="done_button" msgid="1759387181766603361">"เสร็จสิ้น"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"การตรวจสอบเครือข่าย"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"อุปกรณ์นี้ได้รับการจัดการโดย: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>\n\nผู้ดูแลระบบของคุณสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ ซึ่งรวมถึงอีเมล แอป และเว็บไซต์ที่มีการรักษาความปลอดภัย\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบของคุณ"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"บุคคลที่สามสามารถตรวจสอบกิจกรรมในเครือข่าย\nของคุณ ซึ่งรวมถึงอีเมล แอป และเว็บไซต์ที่มีการรักษาความปลอดภัย\n\nการดำเนินการนี้เกิดขึ้นได้ด้วยข้อมูลรับรองที่เชื่อถือได้ที่ติดตั้งอยู่ในอุปกรณ์ของคุณ"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"ตรวจสอบข้อมูลรับรองที่เชื่อถือได้"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 69b5aff..33bd368 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Maaaring sinusubaybayan ang network"</string>
- <string name="done_button" msgid="1759387181766603361">"Tapos na"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Pagsubaybay sa Network"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Ang device na ito ay pinamamahalaan ng: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nMay kakayahan ang iyong administrator na subaybayan ang gawain ng iyong network, kasama ang mga email, apps, at secure na mga website.\n\nPara sa higit pang impormasyon, makipag-ugnay sa iyong administrator."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"May kakayahan ang third party na subaybayan ang gawain ng iyong\nnetwork, kasama ang mga email, apps, at secure na mga website.\n\nGinagawa itong posible ng pinagkakatiwalaang kredensyal na naka-install sa iyong device."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Suriin ang mga pinagkakatiwalaang kredensyal"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 67e2be2..fcc5a97 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Parlaklık"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATİK"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ağ izlenebilir"</string>
- <string name="done_button" msgid="1759387181766603361">"Bitti"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Ağ İzleme"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Bu cihazı yöneten alan adı: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nE-postalarınız, uygulamalarınız ve güvenli web siteleriniz dahil olmak üzere ağ etkinlikleriniz yöneticiniz tarafından izlenebilir.\n\nDaha fazla bilgi için yöneticinizle görüşün."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"E-postalarınız, uygulamalarınız ve güvenli web siteleriniz\ndahil olmak üzere ağ etkinliğiniz üçüncü bir tarafça izlenebilir.\n\nCihazınızda yüklü güvenilir bir kimlik bilgisi bunu mümkün kılmaktadır."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Güvenilen kimlik bilgilerini kontrol et"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 527525e..b1d8a39 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яскравість"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мережу можуть відстежувати"</string>
- <string name="done_button" msgid="1759387181766603361">"Готово"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Відстеження мережі"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Цим пристроєм керує домен <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nАдміністратор може відстежувати ваші дії в мережі, зокрема електронне листування, роботу в програмах і на захищених веб-сайтах.\n\nЩоб дізнатися більше, зверніться до свого адміністратора."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Третя сторона може відстежувати ваші дії в\nмережі, зокрема електронне листування, роботу в програмах і на захищених веб-сайтах, за допомогою надійних облікових даних, установлених на вашому пристрої.\n\n"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Переглянути надійні облікові дані"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 4be1bf0..6a079b3 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Độ sáng"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mạng có thể được giám sát"</string>
- <string name="done_button" msgid="1759387181766603361">"Xong"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Giám sát mạng"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Thiết bị này được quản lý bởi: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nQuản trị viên của bạn có thể giám sát hoạt động trên mạng của bạn, bao gồm email, ứng dụng và trang web bảo mật.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Bên thứ ba có thể giám sát hoạt động trên mạng\ncủa bạn, bao gồm email, ứng dụng và trang web bảo mật.\n\nMột bằng chứng xác thực tin cậy được cài đặt trên thiết bị của bạn có thể dẫn đến khả năng này."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Kiểm tra bằng chứng xác thực tin cậy"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 1093d0c..017c8fc 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -156,8 +156,8 @@
<string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"闹钟已设置为:<xliff:g id="TIME">%s</xliff:g>。"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G 数据网络已停用"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G 数据网络已停用"</string>
- <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"移动数据已停用"</string>
- <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"数据已停用"</string>
+ <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"移动数据网络已停用"</string>
+ <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"数据网络已停用"</string>
<string name="data_usage_disabled_dialog" msgid="3853117269051806280">"您已达到指定的数据流量上限。\n\n如果您重新启用数据,运营商可能会收取相应的费用。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"重新启用数据连接"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
@@ -178,10 +178,10 @@
<string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"充电完成"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"蓝牙"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"蓝牙(<xliff:g id="NUMBER">%d</xliff:g> 台设备)"</string>
- <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"蓝牙已关闭"</string>
+ <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"蓝牙:关闭"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"亮度"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自动旋转"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"屏幕方向已锁定"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"屏幕方向:锁定"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"输入法"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"位置信息"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"位置信息服务已关闭"</string>
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"网络可能会受到监控"</string>
- <string name="done_button" msgid="1759387181766603361">"完成"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"网络监控"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"此设备由以下企业域管理:<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>。\n\n您的管理员可以监控您的网络活动,包括收发电子邮件、使用应用和浏览安全网站。\n\n如要了解详情,请与您的管理员联系。"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"第三方可以监控您的网络活动,包括\n收发电子邮件、使用应用和浏览安全网站。\n\n如果您在设备上安装受信任的凭据,就可能出现这种情况。"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"查看受信任的凭据"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index daef9d2..ae816380 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網絡可能會受到監控"</string>
- <string name="done_button" msgid="1759387181766603361">"完成"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"網絡監控"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"這部裝置由下列網域管理:<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>。\n\n您的管理員可以監控您的網絡活動,包括收發電郵、使用應用程式及瀏覽安全網站。\n\n詳情請與您的管理員聯絡。"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"第三方可以監察您的網絡活動,\n包括收發電郵、使用應用程式及瀏覽安全網站。\n\n當裝置安裝了信任的憑證,便可能會出現這種情況。"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"檢查信任的憑證"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 73871c6..4f86806 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -200,9 +200,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網路可能會受到監控"</string>
- <string name="done_button" msgid="1759387181766603361">"完成"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"網路監控"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"這個裝置由下列網域管理:<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>。\n\n您的管理員可以監控您的網路活動,包括收發電子郵件、使用應用程式及瀏覽安全網站。\n\n如需詳細資訊,請與您的管理員聯絡。"</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"第三方可以監控您的網路活動,\n包括收發電子郵件、使用應用程式及瀏覽安全網站。\n\n如果您在裝置上安裝信任的憑證,就會造成這種情況。"</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"檢查信任的憑證"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 6bf89e8..def73ff 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -198,9 +198,4 @@
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ukugqama"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OKUZENZAKALELAYO"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Inethiwekhi ingase inganyelwe"</string>
- <string name="done_button" msgid="1759387181766603361">"Kwenziwe"</string>
- <string name="ssl_ca_cert_dialog_title" msgid="1273796967092027291">"Ukwenganyelwa kwenethiwekhi"</string>
- <string name="ssl_ca_cert_info_message" msgid="5430320539555358452">"Le divayisi iphethwe ngu-: <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>.\n\nUmphathi wakho uyakwazi ukungamela umsebenzi wenethiwekhi yakho, okufaka phakathi ama-imeyili, izinhlelo zokusebenza, namawebhusayithi aphephile.\n\nUkuze uthole olunye ulwazi xhumana nomphathi wakho."</string>
- <string name="ssl_ca_cert_warning_message" msgid="2033091656129963669">"Inkampani yangaphandle ingakwazi ukungamela umsebenzi wenethiwekhi yakho\n, okufaka phakathi ama-imeyili, izinhlelo zokusebenza namawebhusayithi aphephile.\n\nIsiqinisekiso esethenjwayo kudivayisi yakho senza lokhu kwenzeke."</string>
- <string name="ssl_ca_cert_settings_button" msgid="7946956977377166709">"Hlola ukuqinisekisa okwethenjwayo"</string>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3ffa6f4..7fdd308 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -431,8 +431,8 @@
<!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is off. [CHAR LIMIT=NONE] -->
<string name="accessibility_rotation_lock_on_portrait">Screen is locked in portrait orientation.</string>
- <!-- Name of the Jelly Bean platlogo screensaver -->
- <string name="jelly_bean_dream_name">BeanFlinger</string>
+ <!-- Name of the K-release easter egg: a display case for all our tastiest desserts. [CHAR LIMIT=30] -->
+ <string name="dessert_case">Dessert Case</string>
<!-- Name of the launcher shortcut icon that allows dreams to be started immediately [CHAR LIMIT=20] -->
<string name="start_dreams">Daydream</string>
@@ -500,16 +500,5 @@
<!-- Shows up when there is a user SSL CA Cert installed on the
device. Indicates to the user that SSL traffic can be intercepted. [CHAR LIMIT=NONE] -->
<string name="ssl_ca_cert_warning">Network may be monitored</string>
- <!-- Button to close the SSL CA cert warning dialog box. [CHAR LIMIT=NONE] -->
- <string name="done_button">Done</string>
- <!-- Title of Dialog warning users of SSL monitoring. [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_dialog_title">Network Monitoring</string>
- <!-- Text of message to show to users whose administrator has installed a SSL CA Cert.
- [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_info_message">This device is managed by: <xliff:g id="managing_domain">%s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity, including emails, apps, and secure websites.\n\nFor more information,contact your administrator.</string>
- <!-- Text of warning to show to users that have a SSL CA Cert installed. [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_warning_message">A third party is capable of monitoring your network\nactivity, including emails, apps, and secure websites.\n\nA trusted credential installed on your device is making this possible.</string>
- <!-- Label on button that will take the user to the Trusted Credentials settings page.
- [CHAR LIMIT=NONE]-->
- <string name="ssl_ca_cert_settings_button">Check trusted credentials</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2257617..2be8ee5 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -292,11 +292,7 @@
c.drawRect(mFrame, mBatteryPaint);
c.restore();
- if (level <= EMPTY) {
- final float x = mWidth * 0.5f;
- final float y = (mHeight + mWarningTextHeight) * 0.48f;
- c.drawText(mWarningString, x, y, mWarningTextPaint);
- } else if (tracker.plugged) {
+ if (tracker.plugged) {
// draw the bolt
final int bl = (int)(mFrame.left + width / 4f);
final int bt = (int)(mFrame.top + height / 6f);
@@ -319,6 +315,10 @@
mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
}
c.drawPath(mBoltPath, mBoltPaint);
+ } else if (level <= EMPTY) {
+ final float x = mWidth * 0.5f;
+ final float y = (mHeight + mWarningTextHeight) * 0.48f;
+ c.drawText(mWarningString, x, y, mWarningTextPaint);
} else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
mTextPaint.setTextSize(height *
(SINGLE_DIGIT_PERCENT ? 0.75f
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCase.java b/packages/SystemUI/src/com/android/systemui/DessertCase.java
new file mode 100644
index 0000000..b6424af0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DessertCase.java
@@ -0,0 +1,37 @@
+/*
+ * 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.systemui;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.util.Slog;
+
+public class DessertCase extends Activity {
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ Slog.v("DessertCase", "ACHIEVEMENT UNLOCKED");
+ PackageManager pm = getPackageManager();
+ pm.setComponentEnabledSetting(new ComponentName(this, DessertCaseDream.class),
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+
+ finish();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java
new file mode 100644
index 0000000..022e4d8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java
@@ -0,0 +1,39 @@
+/*
+ * 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.systemui;
+
+import android.service.dreams.DreamService;
+
+public class DessertCaseDream extends DreamService {
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ setInteractive(true);
+ setFullscreen(true);
+ }
+
+ @Override
+ public void onDreamingStarted() {
+ super.onDreamingStarted();
+ }
+
+ @Override
+ public void onDreamingStopped() {
+ super.onDreamingStopped();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
new file mode 100644
index 0000000..b4d3edd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.recent;
+
+import android.graphics.drawable.ColorDrawable;
+
+public class ColorDrawableWithDimensions extends ColorDrawable {
+ private int mWidth;
+ private int mHeight;
+
+ public ColorDrawableWithDimensions(int color, int width, int height) {
+ super(color);
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mHeight;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 8b2cd3f..c714d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -25,7 +25,7 @@
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
@@ -62,8 +62,8 @@
private Handler mHandler;
private int mIconDpi;
- private Bitmap mDefaultThumbnailBackground;
- private Bitmap mDefaultIconBackground;
+ private ColorDrawableWithDimensions mDefaultThumbnailBackground;
+ private ColorDrawableWithDimensions mDefaultIconBackground;
private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
private boolean mFirstScreenful;
@@ -100,7 +100,7 @@
// Render default icon (just a blank image)
int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
- mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+ mDefaultIconBackground = new ColorDrawableWithDimensions(0x00000000, iconSize, iconSize);
// Render the default thumbnail background
int thumbnailWidth =
@@ -110,9 +110,7 @@
int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
mDefaultThumbnailBackground =
- Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(mDefaultThumbnailBackground);
- c.drawColor(color);
+ new ColorDrawableWithDimensions(color, thumbnailWidth, thumbnailHeight);
}
public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
@@ -125,11 +123,11 @@
}
}
- public Bitmap getDefaultThumbnail() {
+ public Drawable getDefaultThumbnail() {
return mDefaultThumbnailBackground;
}
- public Bitmap getDefaultIcon() {
+ public Drawable getDefaultIcon() {
return mDefaultIconBackground;
}
@@ -199,7 +197,7 @@
+ td + ": " + thumbnail);
synchronized (td) {
if (thumbnail != null) {
- td.setThumbnail(thumbnail);
+ td.setThumbnail(new BitmapDrawable(mContext.getResources(), thumbnail));
} else {
td.setThumbnail(mDefaultThumbnailBackground);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index f51e34b..f5670e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -22,7 +22,10 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -68,7 +71,14 @@
}
} else {
- Bitmap first = firstTask.getThumbnail();
+ Bitmap first = null;
+ if (firstTask.getThumbnail() instanceof BitmapDrawable) {
+ first = ((BitmapDrawable) firstTask.getThumbnail()).getBitmap();
+ } else {
+ first = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ Drawable d = RecentTasksLoader.getInstance(mContext).getDefaultThumbnail();
+ d.draw(new Canvas(first));
+ }
final Resources res = mContext.getResources();
float thumbWidth = res
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index ada30ac..918f4a4 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -23,6 +23,7 @@
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.TaskStackBuilder;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -112,7 +113,7 @@
/* package */ final static class ViewHolder {
View thumbnailView;
ImageView thumbnailViewImage;
- Bitmap thumbnailViewImageBitmap;
+ Drawable thumbnailViewDrawable;
ImageView iconView;
TextView labelView;
TextView descriptionView;
@@ -150,7 +151,7 @@
// the thumbnail later (if they both have the same dimensions)
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
- holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -226,7 +227,7 @@
public void recycleView(View v) {
ViewHolder holder = (ViewHolder) v.getTag();
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
- holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+ holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
holder.iconView.setVisibility(INVISIBLE);
holder.iconView.animate().cancel();
holder.labelView.setText(null);
@@ -487,23 +488,23 @@
}
}
- private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
+ private void updateThumbnail(ViewHolder h, Drawable thumbnail, boolean show, boolean anim) {
if (thumbnail != null) {
// Should remove the default image in the frame
// that this now covers, to improve scrolling speed.
// That can't be done until the anim is complete though.
- h.thumbnailViewImage.setImageBitmap(thumbnail);
+ h.thumbnailViewImage.setImageDrawable(thumbnail);
// scale the image to fill the full width of the ImageView. do this only if
// we haven't set a bitmap before, or if the bitmap size has changed
- if (h.thumbnailViewImageBitmap == null ||
- h.thumbnailViewImageBitmap.getWidth() != thumbnail.getWidth() ||
- h.thumbnailViewImageBitmap.getHeight() != thumbnail.getHeight()) {
+ if (h.thumbnailViewDrawable == null ||
+ h.thumbnailViewDrawable.getIntrinsicWidth() != thumbnail.getIntrinsicWidth() ||
+ h.thumbnailViewDrawable.getIntrinsicHeight() != thumbnail.getIntrinsicHeight()) {
if (mFitThumbnailToXY) {
h.thumbnailViewImage.setScaleType(ScaleType.FIT_XY);
} else {
Matrix scaleMatrix = new Matrix();
- float scale = mThumbnailWidth / (float) thumbnail.getWidth();
+ float scale = mThumbnailWidth / (float) thumbnail.getIntrinsicWidth();
scaleMatrix.setScale(scale, scale);
h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
h.thumbnailViewImage.setImageMatrix(scaleMatrix);
@@ -516,7 +517,7 @@
}
h.thumbnailView.setVisibility(View.VISIBLE);
}
- h.thumbnailViewImageBitmap = thumbnail;
+ h.thumbnailViewDrawable = thumbnail;
}
}
@@ -662,20 +663,24 @@
}
public void handleOnClick(View view) {
- ViewHolder holder = (ViewHolder)view.getTag();
+ ViewHolder holder = (ViewHolder) view.getTag();
TaskDescription ad = holder.taskDescription;
final Context context = view.getContext();
final ActivityManager am = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
- Bitmap bm = holder.thumbnailViewImageBitmap;
- boolean usingDrawingCache;
- if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
- bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
- usingDrawingCache = false;
- } else {
+
+ Bitmap bm = null;
+ boolean usingDrawingCache = true;
+ if (holder.thumbnailViewDrawable instanceof BitmapDrawable) {
+ bm = ((BitmapDrawable) holder.thumbnailViewDrawable).getBitmap();
+ if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
+ bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
+ usingDrawingCache = false;
+ }
+ }
+ if (usingDrawingCache) {
holder.thumbnailViewImage.setDrawingCacheEnabled(true);
bm = holder.thumbnailViewImage.getDrawingCache();
- usingDrawingCache = true;
}
Bundle opts = (bm == null) ?
null :
@@ -698,6 +703,8 @@
new UserHandle(UserHandle.USER_CURRENT));
} catch (SecurityException e) {
Log.e(TAG, "Recents does not have the permission to launch " + intent, e);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Error launching activity " + intent, e);
}
}
if (usingDrawingCache) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
index 7e979b7..2bc2821 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
@@ -29,7 +29,7 @@
final String packageName; // used to override animations (see onClick())
final CharSequence description;
- private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
+ private Drawable mThumbnail; // generated by Activity.onCreateThumbnail()
private Drawable mIcon; // application package icon
private CharSequence mLabel; // application package label
private boolean mLoaded;
@@ -85,11 +85,11 @@
mIcon = icon;
}
- public void setThumbnail(Bitmap thumbnail) {
+ public void setThumbnail(Drawable thumbnail) {
mThumbnail = thumbnail;
}
- public Bitmap getThumbnail() {
+ public Drawable getThumbnail() {
return mThumbnail;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 6302244..212d704 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -20,7 +20,6 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.ActivityManager;
-import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -35,6 +34,10 @@
public static final int MODE_OPAQUE = 0;
public static final int MODE_SEMI_TRANSPARENT = 1;
public static final int MODE_TRANSPARENT = 2;
+ public static final int MODE_LIGHTS_OUT = 3;
+
+ protected static final int LIGHTS_IN_DURATION = 250;
+ protected static final int LIGHTS_OUT_DURATION = 750;
private final String mTag;
protected final View mTarget;
@@ -52,10 +55,10 @@
}
};
- public BarTransitions(Context context, View target) {
+ public BarTransitions(View target) {
mTag = "BarTransitions." + target.getClass().getSimpleName();
mTarget = target;
- final Resources res = context.getResources();
+ final Resources res = target.getContext().getResources();
mOpaque = res.getColor(R.drawable.status_bar_background);
mSemiTransparent = res.getColor(R.color.status_bar_background_semi_transparent);
}
@@ -76,6 +79,7 @@
protected Integer getBackgroundColor(int mode) {
if (mode == MODE_SEMI_TRANSPARENT) return mSemiTransparent;
if (mode == MODE_OPAQUE) return mOpaque;
+ if (mode == MODE_LIGHTS_OUT) return mOpaque;
return null;
}
@@ -113,6 +117,7 @@
if (mode == MODE_OPAQUE) return "MODE_OPAQUE";
if (mode == MODE_SEMI_TRANSPARENT) return "MODE_SEMI_TRANSPARENT";
if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT";
+ if (mode == MODE_LIGHTS_OUT) return "MODE_LIGHTS_OUT";
throw new IllegalArgumentException("Unknown mode " + mode);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
new file mode 100644
index 0000000..085130b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -0,0 +1,163 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.GradientDrawable.Orientation;
+import android.os.ServiceManager;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+public final class NavigationBarTransitions extends BarTransitions {
+ private static final boolean ENABLE_GRADIENT = false; // until we can smooth transition
+
+ private final NavigationBarView mView;
+ private final Drawable mTransparentBottom;
+ private final Drawable mTransparentRight;
+ private final int mTransparentColor;
+ private final IStatusBarService mBarService;
+
+ private boolean mLightsOut;
+
+ public NavigationBarTransitions(NavigationBarView view) {
+ super(view);
+ mView = view;
+ final Resources res = mView.getContext().getResources();
+ final int[] gradientColors = new int[] {
+ res.getColor(R.color.navigation_bar_background_transparent_start),
+ res.getColor(R.color.navigation_bar_background_transparent_end)
+ };
+ mTransparentBottom = new GradientDrawable(Orientation.BOTTOM_TOP, gradientColors);
+ mTransparentRight = new GradientDrawable(Orientation.RIGHT_LEFT, gradientColors);
+ mTransparentColor = res.getColor(R.color.status_bar_background_transparent);
+ mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ }
+
+ public void setVertical(boolean isVertical) {
+ if (!ENABLE_GRADIENT) return;
+ mTransparent = isVertical ? mTransparentRight : mTransparentBottom;
+ }
+
+ @Override
+ protected Integer getBackgroundColor(int mode) {
+ if (!ENABLE_GRADIENT && mode == MODE_TRANSPARENT) return mTransparentColor;
+ return super.getBackgroundColor(mode);
+ }
+
+ @Override
+ protected void onTransition(int oldMode, int newMode, boolean animate) {
+ super.onTransition(oldMode, newMode, animate);
+ applyMode(newMode, animate, false /*force*/);
+ }
+
+ public void reapplyMode() {
+ applyMode(getMode(), false /*animate*/, true /*force*/);
+ }
+
+ private void applyMode(int mode, boolean animate, boolean force) {
+ // apply to key buttons
+ final boolean isOpaque = mode == MODE_OPAQUE || mode == MODE_LIGHTS_OUT;
+ final float alpha = isOpaque ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f;
+ setKeyButtonViewQuiescentAlpha(mView.getBackButton(), alpha, animate);
+ setKeyButtonViewQuiescentAlpha(mView.getHomeButton(), alpha, animate);
+ setKeyButtonViewQuiescentAlpha(mView.getRecentsButton(), alpha, animate);
+ setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate);
+
+ // apply to lights out
+ applyLightsOut(mode == MODE_LIGHTS_OUT, animate, force);
+ }
+
+ private void setKeyButtonViewQuiescentAlpha(View button, float alpha, boolean animate) {
+ if (button instanceof KeyButtonView) {
+ ((KeyButtonView) button).setQuiescentAlpha(alpha, animate);
+ }
+ }
+
+ private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) {
+ if (!force && lightsOut == mLightsOut) return;
+
+ mLightsOut = lightsOut;
+
+ final View navButtons = mView.getCurrentView().findViewById(R.id.nav_buttons);
+ final View lowLights = mView.getCurrentView().findViewById(R.id.lights_out);
+
+ // ok, everyone, stop it right there
+ navButtons.animate().cancel();
+ lowLights.animate().cancel();
+
+ final float navButtonsAlpha = lightsOut ? 0f : 1f;
+ final float lowLightsAlpha = lightsOut ? 1f : 0f;
+
+ if (!animate) {
+ navButtons.setAlpha(navButtonsAlpha);
+ lowLights.setAlpha(lowLightsAlpha);
+ lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
+ } else {
+ final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
+ navButtons.animate()
+ .alpha(navButtonsAlpha)
+ .setDuration(duration)
+ .start();
+
+ lowLights.setOnTouchListener(mLightsOutListener);
+ if (lowLights.getVisibility() == View.GONE) {
+ lowLights.setAlpha(0f);
+ lowLights.setVisibility(View.VISIBLE);
+ }
+ lowLights.animate()
+ .alpha(lowLightsAlpha)
+ .setDuration(duration)
+ .setInterpolator(new AccelerateInterpolator(2.0f))
+ .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator _a) {
+ lowLights.setVisibility(View.GONE);
+ }
+ })
+ .start();
+ }
+ }
+
+ private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ // even though setting the systemUI visibility below will turn these views
+ // on, we need them to come up faster so that they can catch this motion
+ // event
+ applyLightsOut(false, false, false);
+
+ try {
+ mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ } catch (android.os.RemoteException ex) {
+ }
+ }
+ return false;
+ }
+ };
+}
\ No newline at end of file
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 850f94d..b56d7be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.app.StatusBarManager;
import android.content.Context;
@@ -25,11 +23,8 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.GradientDrawable.Orientation;
import android.os.Handler;
import android.os.Message;
-import android.os.ServiceManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
@@ -38,16 +33,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.DelegateViewHelper;
import com.android.systemui.statusbar.policy.DeadZone;
-import com.android.systemui.statusbar.policy.KeyButtonView;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -59,11 +51,8 @@
final static boolean NAVBAR_ALWAYS_AT_RIGHT = true;
// slippery nav bar when everything is disabled, e.g. during setup
- final static boolean SLIPPERY_WHEN_DISABLED= true;
+ final static boolean SLIPPERY_WHEN_DISABLED = true;
- final static boolean ANIMATE_HIDE_TRANSITION = false; // turned off because it introduces unsightly delay when videos goes to full screen
-
- protected IStatusBarService mBarService;
final Display mDisplay;
View mCurrentView = null;
View[] mRotatedViews = new View[4];
@@ -72,7 +61,7 @@
boolean mVertical;
boolean mScreenOn;
- boolean mHidden, mLowProfile, mShowMenu;
+ boolean mShowMenu;
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
@@ -111,62 +100,11 @@
}
}
- private final class NavigationBarTransitions extends BarTransitions {
- private static final boolean ENABLE_GRADIENT = false; // until we can smooth transition
-
- private final Drawable mTransparentBottom;
- private final Drawable mTransparentRight;
- private final int mTransparentColor;
-
- public NavigationBarTransitions(Context context) {
- super(context, NavigationBarView.this);
- final Resources res = mContext.getResources();
- final int[] gradientColors = new int[] {
- res.getColor(R.color.navigation_bar_background_transparent_start),
- res.getColor(R.color.navigation_bar_background_transparent_end)
- };
- mTransparentBottom = new GradientDrawable(Orientation.BOTTOM_TOP, gradientColors);
- mTransparentRight = new GradientDrawable(Orientation.RIGHT_LEFT, gradientColors);
- mTransparentColor = res.getColor(R.color.status_bar_background_transparent);
- }
-
- public void setVertical(boolean isVertical) {
- if (!ENABLE_GRADIENT) return;
- mTransparent = isVertical ? mTransparentRight : mTransparentBottom;
- }
-
- @Override
- protected Integer getBackgroundColor(int mode) {
- if (!ENABLE_GRADIENT && mode == MODE_TRANSPARENT) return mTransparentColor;
- return super.getBackgroundColor(mode);
- }
-
- @Override
- protected void onTransition(int oldMode, int newMode, boolean animate) {
- super.onTransition(oldMode, newMode, animate);
- final float alpha = newMode == MODE_OPAQUE ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f;
- setKeyButtonViewQuiescentAlpha(getBackButton(), alpha);
- setKeyButtonViewQuiescentAlpha(getHomeButton(), alpha);
- setKeyButtonViewQuiescentAlpha(getRecentsButton(), alpha);
- setKeyButtonViewQuiescentAlpha(getMenuButton(), alpha);
- }
-
- private void setKeyButtonViewQuiescentAlpha(View button, float alpha) {
- if (button instanceof KeyButtonView) {
- ((KeyButtonView) button).setQuiescentAlpha(alpha);
- }
- }
- }
-
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
- mHidden = false;
-
mDisplay = ((WindowManager)context.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
final Resources res = mContext.getResources();
mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
@@ -176,7 +114,7 @@
getIcons(res);
- mBarTransitions = new NavigationBarTransitions(context);
+ mBarTransitions = new NavigationBarTransitions(this);
}
public BarTransitions getBarTransitions() {
@@ -210,6 +148,10 @@
private H mHandler = new H();
+ public View getCurrentView() {
+ return mCurrentView;
+ }
+
public View getRecentsButton() {
return mCurrentView.findViewById(R.id.recent_apps);
}
@@ -252,24 +194,6 @@
setDisabledFlags(mDisabledFlags, true);
}
- View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- // even though setting the systemUI visibility below will turn these views
- // on, we need them to come up faster so that they can catch this motion
- // event
- setLowProfile(false, false, false);
-
- try {
- mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
- } catch (android.os.RemoteException ex) {
- }
- }
- return false;
- }
- };
-
public void setNavigationIconHints(int hints) {
setNavigationIconHints(hints, false);
}
@@ -366,65 +290,6 @@
getMenuButton().setVisibility(mShowMenu ? View.VISIBLE : View.INVISIBLE);
}
- public void setLowProfile(final boolean lightsOut) {
- setLowProfile(lightsOut, true, false);
- }
-
- public void setLowProfile(final boolean lightsOut, final boolean animate, final boolean force) {
- if (!force && lightsOut == mLowProfile) return;
-
- mLowProfile = lightsOut;
-
- if (DEBUG) Log.d(TAG, "setting lights " + (lightsOut?"out":"on"));
-
- final View navButtons = mCurrentView.findViewById(R.id.nav_buttons);
- final View lowLights = mCurrentView.findViewById(R.id.lights_out);
-
- // ok, everyone, stop it right there
- navButtons.animate().cancel();
- lowLights.animate().cancel();
-
- if (!animate) {
- navButtons.setAlpha(lightsOut ? 0f : 1f);
-
- lowLights.setAlpha(lightsOut ? 1f : 0f);
- lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
- } else {
- navButtons.animate()
- .alpha(lightsOut ? 0f : 1f)
- .setDuration(lightsOut ? 750 : 250)
- .start();
-
- lowLights.setOnTouchListener(mLightsOutListener);
- if (lowLights.getVisibility() == View.GONE) {
- lowLights.setAlpha(0f);
- lowLights.setVisibility(View.VISIBLE);
- }
- lowLights.animate()
- .alpha(lightsOut ? 1f : 0f)
- .setDuration(lightsOut ? 750 : 250)
- .setInterpolator(new AccelerateInterpolator(2.0f))
- .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator _a) {
- lowLights.setVisibility(View.GONE);
- }
- })
- .start();
- }
- }
-
- public void setHidden(final boolean hide) {
- if (hide == mHidden) return;
-
- mHidden = hide;
- Log.d(TAG,
- (hide ? "HIDING" : "SHOWING") + " navigation bar");
-
- // bring up the lights no matter what
- setLowProfile(false);
- }
-
@Override
public void onFinishInflate() {
mRotatedViews[Surface.ROTATION_0] =
@@ -454,7 +319,7 @@
mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
// force the low profile & disabled states into compliance
- setLowProfile(mLowProfile, false, true /* force */);
+ mBarTransitions.reapplyMode();
setDisabledFlags(mDisabledFlags, true /* force */);
setMenuVisibility(mShowMenu, true /* force */);
@@ -559,11 +424,9 @@
mCurrentView.getWidth(), mCurrentView.getHeight(),
visibilityToString(mCurrentView.getVisibility())));
- pw.println(String.format(" disabled=0x%08x vertical=%s hidden=%s low=%s menu=%s",
+ pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s",
mDisabledFlags,
mVertical ? "true" : "false",
- mHidden ? "true" : "false",
- mLowProfile ? "true" : "false",
mShowMenu ? "true" : "false"));
final View back = getBackButton();
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 64d4c7f..d15626b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -17,15 +17,16 @@
package com.android.systemui.statusbar.phone;
import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.app.ActivityManager;
@@ -251,9 +252,6 @@
int[] mAbsPos = new int[2];
Runnable mPostCollapseCleanup = null;
- private Animator mLightsOutAnimation;
- private Animator mLightsOnAnimation;
-
// for disabling the status bar
int mDisabled = 0;
@@ -1380,6 +1378,14 @@
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
+ private void releaseFocus() {
+ WindowManager.LayoutParams lp =
+ (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
+ lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mWindowManager.updateViewLayout(mStatusBarWindow, lp);
+ }
+
public void animateCollapsePanels() {
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
}
@@ -1391,6 +1397,9 @@
+ " flags=" + flags);
}
+ // release focus immediately to kick off focus change transition
+ releaseFocus();
+
if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
@@ -1808,11 +1817,7 @@
}
}
- if (mNavigationBarView != null) {
- mNavigationBarView.setLowProfile(lightsOut);
- }
-
- setStatusBarLowProfile(lightsOut);
+ setAreThereNotifications();
}
// update status bar mode
@@ -1872,6 +1877,7 @@
private int barMode(int vis, int transientFlag, int transparentFlag) {
return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
: (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
+ : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
: MODE_OPAQUE;
}
@@ -1888,7 +1894,7 @@
private void checkBarMode(int mode, int windowState, BarTransitions transitions) {
final boolean imeVisible = (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0;
final int finalMode = imeVisible ? MODE_OPAQUE : mode;
- final boolean animate = windowState == WINDOW_STATE_SHOWING;
+ final boolean animate = windowState != WINDOW_STATE_HIDDEN;
transitions.transitionTo(finalMode, animate);
}
@@ -1948,47 +1954,6 @@
mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
}
- private void setStatusBarLowProfile(boolean lightsOut) {
- if (mLightsOutAnimation == null) {
- final View notifications = mStatusBarView.findViewById(R.id.notification_icon_area);
- final View systemIcons = mStatusBarView.findViewById(R.id.statusIcons);
- final View signal = mStatusBarView.findViewById(R.id.signal_cluster);
- final View battery = mStatusBarView.findViewById(R.id.battery);
- final View clock = mStatusBarView.findViewById(R.id.clock);
-
- final AnimatorSet lightsOutAnim = new AnimatorSet();
- lightsOutAnim.playTogether(
- ObjectAnimator.ofFloat(notifications, View.ALPHA, 0),
- ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 0),
- ObjectAnimator.ofFloat(signal, View.ALPHA, 0),
- ObjectAnimator.ofFloat(battery, View.ALPHA, 0.5f),
- ObjectAnimator.ofFloat(clock, View.ALPHA, 0.5f)
- );
- lightsOutAnim.setDuration(750);
-
- final AnimatorSet lightsOnAnim = new AnimatorSet();
- lightsOnAnim.playTogether(
- ObjectAnimator.ofFloat(notifications, View.ALPHA, 1),
- ObjectAnimator.ofFloat(systemIcons, View.ALPHA, 1),
- ObjectAnimator.ofFloat(signal, View.ALPHA, 1),
- ObjectAnimator.ofFloat(battery, View.ALPHA, 1),
- ObjectAnimator.ofFloat(clock, View.ALPHA, 1)
- );
- lightsOnAnim.setDuration(250);
-
- mLightsOutAnimation = lightsOutAnim;
- mLightsOnAnimation = lightsOnAnim;
- }
-
- mLightsOutAnimation.cancel();
- mLightsOnAnimation.cancel();
-
- final Animator a = lightsOut ? mLightsOutAnimation : mLightsOnAnimation;
- a.start();
-
- setAreThereNotifications();
- }
-
private boolean areLightsOn() {
return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
new file mode 100644
index 0000000..b9ffd6e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -0,0 +1,117 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.R;
+
+public final class PhoneStatusBarTransitions extends BarTransitions {
+ private static final float ALPHA_WHEN_TRANSPARENT = 1;
+ private static final float ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK = 0.5f;
+ private static final float ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK = 0;
+
+ private final PhoneStatusBarView mView;
+ private final int mTransparent;
+ private final float mAlphaWhenOpaque;
+
+ private View mLeftSide, mStatusIcons, mSignalCluster, mBattery, mClock;
+ private Animator mCurrentAnimation;
+
+ public PhoneStatusBarTransitions(PhoneStatusBarView view) {
+ super(view);
+ mView = view;
+ final Resources res = mView.getContext().getResources();
+ mTransparent = res.getColor(R.color.status_bar_background_transparent);
+ mAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
+ }
+
+ public void init() {
+ mLeftSide = mView.findViewById(R.id.notification_icon_area);
+ mStatusIcons = mView.findViewById(R.id.statusIcons);
+ mSignalCluster = mView.findViewById(R.id.signal_cluster);
+ mBattery = mView.findViewById(R.id.battery);
+ mClock = mView.findViewById(R.id.clock);
+ applyMode(getMode(), false /*animate*/);
+ }
+
+ @Override
+ protected Integer getBackgroundColor(int mode) {
+ if (mode == MODE_TRANSPARENT) return mTransparent;
+ return super.getBackgroundColor(mode);
+ }
+
+ public ObjectAnimator animateTransitionTo(View v, float toAlpha) {
+ return ObjectAnimator.ofFloat(v, "alpha", v.getAlpha(), toAlpha);
+ }
+
+ private float getNonBatteryClockAlphaFor(int mode) {
+ return mode == MODE_LIGHTS_OUT ? ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK
+ : isTransparent(mode) ? ALPHA_WHEN_TRANSPARENT
+ : mAlphaWhenOpaque;
+ }
+
+ private float getBatteryClockAlpha(int mode) {
+ return mode == MODE_LIGHTS_OUT ? ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK
+ : getNonBatteryClockAlphaFor(mode);
+ }
+
+ private boolean isTransparent(int mode) {
+ return mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSPARENT;
+ }
+
+ @Override
+ protected void onTransition(int oldMode, int newMode, boolean animate) {
+ super.onTransition(oldMode, newMode, animate);
+ applyMode(newMode, animate);
+ }
+
+ private void applyMode(int mode, boolean animate) {
+ if (mLeftSide == null) return; // pre-init
+ float newAlpha = getNonBatteryClockAlphaFor(mode);
+ float newAlphaBC = getBatteryClockAlpha(mode);
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.cancel();
+ }
+ if (animate) {
+ AnimatorSet anims = new AnimatorSet();
+ anims.playTogether(
+ animateTransitionTo(mLeftSide, newAlpha),
+ animateTransitionTo(mStatusIcons, newAlpha),
+ animateTransitionTo(mSignalCluster, newAlpha),
+ animateTransitionTo(mBattery, newAlphaBC),
+ animateTransitionTo(mClock, newAlphaBC)
+ );
+ if (mode == MODE_LIGHTS_OUT) {
+ anims.setDuration(LIGHTS_OUT_DURATION);
+ }
+ anims.start();
+ mCurrentAnimation = anims;
+ } else {
+ mLeftSide.setAlpha(newAlpha);
+ mStatusIcons.setAlpha(newAlpha);
+ mSignalCluster.setAlpha(newAlpha);
+ mBattery.setAlpha(newAlphaBC);
+ mClock.setAlpha(newAlphaBC);
+ }
+ }
+}
\ No newline at end of file
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 b263a6e..d9ac7e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
@@ -47,73 +45,7 @@
PanelView mLastFullyOpenedPanel = null;
PanelView mNotificationPanel, mSettingsPanel;
private boolean mShouldFade;
- private final StatusBarTransitions mBarTransitions;
-
- private final class StatusBarTransitions extends BarTransitions {
- private final int mTransparent;
- private final float mAlphaWhenOpaque;
- private final float mAlphaWhenTransparent = 1;
- private View mLeftSide, mStatusIcons, mSignalCluster, mClock;
-
- public StatusBarTransitions(Context context) {
- super(context, PhoneStatusBarView.this);
- final Resources res = context.getResources();
- mTransparent = res.getColor(R.color.status_bar_background_transparent);
- mAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1);
- }
-
- public void init() {
- mLeftSide = findViewById(R.id.notification_icon_area);
- mStatusIcons = findViewById(R.id.statusIcons);
- mSignalCluster = findViewById(R.id.signal_battery_cluster);
- mClock = findViewById(R.id.clock);
- applyMode(getMode(), false /*animate*/);
- }
-
- @Override
- protected Integer getBackgroundColor(int mode) {
- if (mode == MODE_TRANSPARENT) return mTransparent;
- return super.getBackgroundColor(mode);
- }
-
- public ObjectAnimator animateTransitionTo(View v, float toAlpha) {
- return ObjectAnimator.ofFloat(v, "alpha", v.getAlpha(), toAlpha);
- }
-
- public float getAlphaFor(int mode) {
- return isTransparent(mode) ? mAlphaWhenTransparent : mAlphaWhenOpaque;
- }
-
- private boolean isTransparent(int mode) {
- return mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSPARENT;
- }
-
- @Override
- protected void onTransition(int oldMode, int newMode, boolean animate) {
- super.onTransition(oldMode, newMode, animate);
- applyMode(newMode, animate);
- }
-
- private void applyMode(int mode, boolean animate) {
- if (mLeftSide == null) return; // pre-init
- float newAlpha = getAlphaFor(mode);
- if (animate) {
- AnimatorSet anims = new AnimatorSet();
- anims.playTogether(
- animateTransitionTo(mLeftSide, newAlpha),
- animateTransitionTo(mStatusIcons, newAlpha),
- animateTransitionTo(mSignalCluster, newAlpha),
- animateTransitionTo(mClock, newAlpha)
- );
- anims.start();
- } else {
- mLeftSide.setAlpha(newAlpha);
- mStatusIcons.setAlpha(newAlpha);
- mSignalCluster.setAlpha(newAlpha);
- mClock.setAlpha(newAlpha);
- }
- }
- }
+ private final PhoneStatusBarTransitions mBarTransitions;
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -127,7 +59,7 @@
mSettingsPanelDragzoneFrac = 0f;
}
mFullWidthNotifications = mSettingsPanelDragzoneFrac <= 0f;
- mBarTransitions = new StatusBarTransitions(context);
+ mBarTransitions = new PhoneStatusBarTransitions(this);
}
public BarTransitions getBarTransitions() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 68ee2b5..25ffbd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -194,7 +194,7 @@
mQueryCertTask = new AsyncTask<Void, Void, Pair<Boolean, Boolean>>() {
@Override
protected Pair<Boolean, Boolean> doInBackground(Void... params) {
- boolean hasCert = mDevicePolicyManager.hasAnyCaCertsInstalled();
+ boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
return Pair.create(hasCert, isManaged);
@@ -671,7 +671,7 @@
alarmTile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- startSettingsActivity(AlarmClock.ACTION_SET_ALARM);
+ startSettingsActivity(AlarmClock.ACTION_SHOW_ALARMS);
}
});
mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
@@ -764,7 +764,7 @@
@Override
public void onClick(View v) {
collapsePanels();
- showSslCaCertWarningDialog();
+ startSettingsActivity(Settings.ACTION_MONITORING_CERT_INFO);
}
});
@@ -832,45 +832,6 @@
dialog.show();
}
- private void showSslCaCertWarningDialog() {
- final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
- builder.setTitle(R.string.ssl_ca_cert_dialog_title);
- builder.setCancelable(true);
- final boolean hasDeviceOwner = mDevicePolicyManager.getDeviceOwner() != null;
- int buttonLabel;
- if (hasDeviceOwner) {
- // Institutional case. Show informational message.
- String message = mContext.getResources().getString(R.string.ssl_ca_cert_info_message,
- mDevicePolicyManager.getDeviceOwnerName());
- builder.setMessage(message);
- buttonLabel = R.string.done_button;
- } else {
- // Consumer case. Show scary warning.
- builder.setMessage(R.string.ssl_ca_cert_warning_message);
- buttonLabel = R.string.ssl_ca_cert_settings_button;
- }
-
- builder.setPositiveButton(buttonLabel, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // do something.
- if (hasDeviceOwner) {
- // Close
- } else {
- startSettingsActivity("com.android.settings.TRUSTED_CREDENTIALS_USER");
- }
- }
- });
-
- final Dialog dialog = builder.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- try {
- WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
- } catch (RemoteException e) {
- }
- dialog.show();
- }
-
private void updateWifiDisplayStatus() {
mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus();
applyWifiDisplayStatus();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 924478c..55fb95d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -17,8 +17,6 @@
package com.android.systemui.statusbar.policy;
import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
@@ -60,6 +58,7 @@
boolean mSupportsLongpress = true;
RectF mRect = new RectF(0f,0f,0f,0f);
AnimatorSet mPressedAnim;
+ Animator mAnimateToQuiescent = new ObjectAnimator();
Runnable mCheckLongPress = new Runnable() {
public void run() {
@@ -76,15 +75,6 @@
}
};
- private final AnimatorListener mRecoverToQuiescentListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mQuiescentAlpha != mDrawingAlpha) {
- animateToQuiescent().setDuration(200).start();
- }
- }
- };
-
public KeyButtonView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -133,16 +123,26 @@
super.onDraw(canvas);
}
- public void setQuiescentAlpha(float alpha) {
+ public void setQuiescentAlpha(float alpha, boolean animate) {
+ mAnimateToQuiescent.cancel();
alpha = Math.min(Math.max(alpha, 0), 1);
if (alpha == mQuiescentAlpha) return;
mQuiescentAlpha = alpha;
if (DEBUG) Log.d(TAG, "New quiescent alpha = " + mQuiescentAlpha);
if (mGlowBG != null) {
- setDrawingAlpha(mQuiescentAlpha);
+ if (animate) {
+ mAnimateToQuiescent = animateToQuiescent();
+ mAnimateToQuiescent.start();
+ } else {
+ setDrawingAlpha(mQuiescentAlpha);
+ }
}
}
+ private ObjectAnimator animateToQuiescent() {
+ return ObjectAnimator.ofFloat(this, "drawingAlpha", mQuiescentAlpha);
+ }
+
public float getDrawingAlpha() {
if (mGlowBG == null) return 0;
return mDrawingAlpha;
@@ -197,12 +197,6 @@
}
}
- private ObjectAnimator animateToQuiescent() {
- ObjectAnimator anim = ObjectAnimator.ofFloat(this, "drawingAlpha", mQuiescentAlpha);
- anim.addListener(mRecoverToQuiescentListener); // mQuiescentAlpha may change mid-animation
- return anim;
- }
-
public void setPressed(boolean pressed) {
if (mGlowBG != null) {
if (pressed != isPressed()) {
@@ -222,10 +216,12 @@
);
as.setDuration(50);
} else {
+ mAnimateToQuiescent.cancel();
+ mAnimateToQuiescent = animateToQuiescent();
as.playTogether(
ObjectAnimator.ofFloat(this, "glowAlpha", 0f),
ObjectAnimator.ofFloat(this, "glowScale", 1f),
- animateToQuiescent()
+ mAnimateToQuiescent
);
as.setDuration(500);
}
diff --git a/packages/VpnDialogs/res/values-en-rIN/strings.xml b/packages/VpnDialogs/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..afc46d8
--- /dev/null
+++ b/packages/VpnDialogs/res/values-en-rIN/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> attempts to create a VPN connection."</string>
+ <string name="warning" msgid="5470743576660160079">"By proceeding, you are giving the application permission to intercept all network traffic. "<b>"Do NOT accept unless you trust the application."</b>" Otherwise, you run the risk of having your data compromised by malicious software."</string>
+ <string name="accept" msgid="2889226408765810173">"I trust this application."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN is connected"</string>
+ <string name="configure" msgid="4905518375574791375">"Configure"</string>
+ <string name="disconnect" msgid="971412338304200056">"Disconnect"</string>
+ <string name="session" msgid="6470628549473641030">"Session:"</string>
+ <string name="duration" msgid="3584782459928719435">"Duration:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Sent:"</string>
+ <string name="data_received" msgid="4062776929376067820">"Received:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> bytes / <xliff:g id="NUMBER_1">%2$s</xliff:g> packets"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-et-rEE/strings.xml b/packages/VpnDialogs/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..c016eb0
--- /dev/null
+++ b/packages/VpnDialogs/res/values-et-rEE/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"Rakenduse <xliff:g id="APP">%s</xliff:g> katsed luua VPN-ühendust."</string>
+ <string name="warning" msgid="5470743576660160079">"Jätkates annate rakendusele loa jälgida kogu võrguliiklust. "<b>"ÄRGE nõustuge, kui te seda rakendust ei usalda."</b>" Vastasel juhul on oht, et pahavara võib kahjustada teie andmeid."</string>
+ <string name="accept" msgid="2889226408765810173">"Usaldan seda rakendust."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN on ühendatud"</string>
+ <string name="configure" msgid="4905518375574791375">"Seadistamine"</string>
+ <string name="disconnect" msgid="971412338304200056">"Katkesta ühendus"</string>
+ <string name="session" msgid="6470628549473641030">"Seansid"</string>
+ <string name="duration" msgid="3584782459928719435">"Kestus:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Saadetud:"</string>
+ <string name="data_received" msgid="4062776929376067820">"Vastu on võetud:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> baiti / <xliff:g id="NUMBER_1">%2$s</xliff:g> paketti"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-fr-rCA/strings.xml b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..1028f83
--- /dev/null
+++ b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> tente de créer une connexion VPN."</string>
+ <string name="warning" msgid="5470743576660160079">"En continuant, vous autorisez l\'application à intercepter l\'ensemble du trafic réseau. "<b>"N\'acceptez PAS, sauf si vous avez confiance en l\'application."</b>"Sinon, vos données risquent d\'être piratées par un logiciel malveillant."</string>
+ <string name="accept" msgid="2889226408765810173">"J\'ai confiance en cette application."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN connecté"</string>
+ <string name="configure" msgid="4905518375574791375">"Configurer"</string>
+ <string name="disconnect" msgid="971412338304200056">"Déconnecter"</string>
+ <string name="session" msgid="6470628549473641030">"Session :"</string>
+ <string name="duration" msgid="3584782459928719435">"Durée :"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Date d\'envoi :"</string>
+ <string name="data_received" msgid="4062776929376067820">"Reçu le :"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> octets / <xliff:g id="NUMBER_1">%2$s</xliff:g> paquets"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-hi/strings.xml b/packages/VpnDialogs/res/values-hi/strings.xml
index e2cb51a..50be98c 100644
--- a/packages/VpnDialogs/res/values-hi/strings.xml
+++ b/packages/VpnDialogs/res/values-hi/strings.xml
@@ -17,8 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> एक VPN कनेक्शन बनाने का प्रयास करता है."</string>
- <string name="warning" msgid="5470743576660160079">"जारी रखकर, आप एप्लिकेशन को सभी नेटवर्क ट्रैफ़िक अवरोधित करने की अनुमति देते हैं. "<b>"जब तक आपको एप्लिकेशन पर विश्वास न हो स्वीकार न करें."</b>" अन्यथा, आपको अपने डेटा के साथ किसी दुर्भावनापूर्ण सॉफ़्टवेयर द्वारा छेड़छाड़ किए जाने का जोखिम हो सकता है."</string>
- <string name="accept" msgid="2889226408765810173">"मुझे इस एप्लिकेशन पर विश्वास है."</string>
+ <string name="warning" msgid="5470743576660160079">"जारी रखकर, आप एप्स को सभी नेटवर्क ट्रैफ़िक अवरोधित करने की अनुमति देते हैं. "<b>"जब तक आपको एप्स पर विश्वास न हो स्वीकार न करें."</b>" अन्यथा, आपको अपने डेटा के साथ किसी दुर्भावनापूर्ण सॉफ़्टवेयर द्वारा छेड़छाड़ किए जाने का जोखिम हो सकता है."</string>
+ <string name="accept" msgid="2889226408765810173">"मुझे इस एप्स पर विश्वास है."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN कनेक्ट है"</string>
<string name="configure" msgid="4905518375574791375">"कॉन्फ़िगर करें"</string>
<string name="disconnect" msgid="971412338304200056">"डिस्कनेक्ट करें"</string>
diff --git a/packages/VpnDialogs/res/values-hy-rAM/strings.xml b/packages/VpnDialogs/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..85db579
--- /dev/null
+++ b/packages/VpnDialogs/res/values-hy-rAM/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"<xliff:g id="APP">%s</xliff:g>-ը փորձում է ստեղծել VPN կապ:"</string>
+ <string name="warning" msgid="5470743576660160079">"Շարունակելով` դուք հավելվածին թույլատրում եք կանգնեցնել ամբողջ ցանցային շարժը: "<b>"Մի ընդունեք, եթե չեք վստահում հավելվածին:"</b>" Այլապես ռիսկ կա ձեր տվյալները վտանգելու վնասարար հավելվածների կողմից:"</string>
+ <string name="accept" msgid="2889226408765810173">"Ես վստահում եմ այս ծրագրին:"</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN-ը կապակցված է"</string>
+ <string name="configure" msgid="4905518375574791375">"Կարգավորել"</string>
+ <string name="disconnect" msgid="971412338304200056">"Անջատել"</string>
+ <string name="session" msgid="6470628549473641030">"Աշխատաշրջան`"</string>
+ <string name="duration" msgid="3584782459928719435">"Տևողությունը՝"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Ուղարկվել է՝"</string>
+ <string name="data_received" msgid="4062776929376067820">"Ստացվել է՝"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> բայթ / <xliff:g id="NUMBER_1">%2$s</xliff:g> փաթեթ"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-ka-rGE/strings.xml b/packages/VpnDialogs/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..960d3f6
--- /dev/null
+++ b/packages/VpnDialogs/res/values-ka-rGE/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> ცდილობს VPN კავშირის შექმნას."</string>
+ <string name="warning" msgid="5470743576660160079">"გაგრძელების შემთხვევაში, აპლიკაციას ექნება ქსელში გადაცემული მონაცემების მოპოვების საშუალება. "<b>"არ განაგრძოთ, თუ არ ენდობით აპლიკაციას."</b>" წინააღმდეგ შემთვევაში შესაძლოა მავნე პროგრამას თქვენ მონაცემებთან წვდომის საშუალება მიეცეს."</string>
+ <string name="accept" msgid="2889226408765810173">"ვენდობი ამ აპლიკაციას."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN დაკავშირებულია"</string>
+ <string name="configure" msgid="4905518375574791375">"კონფიგურაცია"</string>
+ <string name="disconnect" msgid="971412338304200056">"კავშირის გაწყვეტა"</string>
+ <string name="session" msgid="6470628549473641030">"სესია:"</string>
+ <string name="duration" msgid="3584782459928719435">"ხანგრძლივობა:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"გაგზავნილი:"</string>
+ <string name="data_received" msgid="4062776929376067820">"მიღებული:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> ბაიტი / <xliff:g id="NUMBER_1">%2$s</xliff:g> პაკეტი"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-km-rKH/strings.xml b/packages/VpnDialogs/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..2c79e26
--- /dev/null
+++ b/packages/VpnDialogs/res/values-km-rKH/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> ព្យាយាមបង្កើតការតភ្ជាប់ VPN ។"</string>
+ <string name="warning" msgid="5470743576660160079">"ដោយបន្ត អ្នកកំពុងផ្ដល់សិទ្ធិឲ្យកម្មវិធីទប់ស្កាត់ចរាចរណ៍បណ្ដាញ។ "<b>"កុំទទួល លុះត្រាតែអ្នកទុកចិត្តកម្មវិធី។"</b>" បើមិនដូច្នេះទេ អ្នកដំណើរការប្រឈមនឹងគ្រោះថ្នាក់ ដោយទិន្នន័យរបស់អ្នកបានសម្របសម្រួលដោយកម្មវិធីព្យាបាទ។"</string>
+ <string name="accept" msgid="2889226408765810173">"ខ្ញុំទុកចិត្តកម្មវិធីនេះ។"</string>
+ <string name="legacy_title" msgid="192936250066580964">"បានភ្ជាប់ VPN"</string>
+ <string name="configure" msgid="4905518375574791375">"កំណត់រចនាសម្ព័ន្ធ"</string>
+ <string name="disconnect" msgid="971412338304200056">"ផ្ដាច់"</string>
+ <string name="session" msgid="6470628549473641030">"សម័យ៖"</string>
+ <string name="duration" msgid="3584782459928719435">"ថិរវេលា៖"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"បានផ្ញើ៖"</string>
+ <string name="data_received" msgid="4062776929376067820">"បានទទួល៖"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> បៃ / <xliff:g id="NUMBER_1">%2$s</xliff:g> កញ្ចប់ព័ត៌មាន"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-lo-rLA/strings.xml b/packages/VpnDialogs/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..9f5216b
--- /dev/null
+++ b/packages/VpnDialogs/res/values-lo-rLA/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> ພະຍາຍາມສ້າງການເຊື່ອມຕໍ່ VPN."</string>
+ <string name="warning" msgid="5470743576660160079">"ຖ້າດຳເນີນຕໍ່, ແມ່ນທ່ານກຳລັງຈະໃຫ້ສິດແກ່ແອັບພລິເຄຊັນ ໃນການດັກຂໍ້ມູນຈະລາຈອນໃນເຄືອຂ່າຍທັງໝົດ. "<b>"ຢ່າຍອມຮັບ ນອກຈາກວ່າທ່ານຈະເຊື່ອໃຈແອັບພລິເຄຊັນດັ່ງກ່າວ."</b>" ຖ້າບໍ່ດັ່ງນັ້ນ, ທ່ານຈະຕົກຢູ່ໃນຄວາມສ່ຽງ ທີ່ຂໍ້ມູນຂອງທ່ານຈະຖືກຄຸກຄາມໂດຍຊອບແວທີ່ເປັນອັນຕະລາຍ."</string>
+ <string name="accept" msgid="2889226408765810173">"ຂ້ອຍເຊື່ອແອັບພລິເຄຊັນນີ້."</string>
+ <string name="legacy_title" msgid="192936250066580964">"ເຊື່ອມຕໍ່ VPN ແລ້ວ"</string>
+ <string name="configure" msgid="4905518375574791375">"ປັບຄ່າ"</string>
+ <string name="disconnect" msgid="971412338304200056">"ຕັດການເຊື່ອມຕໍ່"</string>
+ <string name="session" msgid="6470628549473641030">"ເຊສຊັນ:"</string>
+ <string name="duration" msgid="3584782459928719435">"ໄລຍະເວລາ:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"ສົ່ງ:"</string>
+ <string name="data_received" msgid="4062776929376067820">"ຮັບ:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> ໄບ / <xliff:g id="NUMBER_1">%2$s</xliff:g> ແພັກເກັດ"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-mn-rMN/strings.xml b/packages/VpnDialogs/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..887bb73
--- /dev/null
+++ b/packages/VpnDialogs/res/values-mn-rMN/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> VPN холболтыг үүсгэх гэж байна."</string>
+ <string name="warning" msgid="5470743576660160079">"Үргэлжлүүлсэнээр та аппликешнд бүх сүлжээний урсгалыг таслах зөвшөөрлийг өгөх болно. "<b>"Аппикешн баталгаагүй гэж үзсэн тохиолдолд л зөвшөөрч болорхгүй."</b>" Бусад тохиолдолд та өөрийн датаг хортой софтверийн аюулд өртөх эрсдэлийг үүсгэж байна."</string>
+ <string name="accept" msgid="2889226408765810173">"Би энэ аппликешнд итгэж байна."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN холбогдов"</string>
+ <string name="configure" msgid="4905518375574791375">"Тохируулах"</string>
+ <string name="disconnect" msgid="971412338304200056">"Салгах"</string>
+ <string name="session" msgid="6470628549473641030">"Сешн:"</string>
+ <string name="duration" msgid="3584782459928719435">"Үргэлжлэх хугацаа:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Илгээсэн:"</string>
+ <string name="data_received" msgid="4062776929376067820">"Хүлээн авсан:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> байт/ <xliff:g id="NUMBER_1">%2$s</xliff:g> пакет"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-ms-rMY/strings.xml b/packages/VpnDialogs/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..417fbae
--- /dev/null
+++ b/packages/VpnDialogs/res/values-ms-rMY/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> percubaan untuk membuat sambungan VPN."</string>
+ <string name="warning" msgid="5470743576660160079">"Dengan meneruskan, anda memberi keizinan kepada aplikasi untuk memintas semua trafik rangkaian. "<b>"JANGAN terima melainkan anda mempercayai aplikasi itu."</b>" Jika tidak, anda akan mengalami risiko data terjejas oleh perisian berniat jahat."</string>
+ <string name="accept" msgid="2889226408765810173">"Saya percayai aplikasi ini."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN telah disambungkan"</string>
+ <string name="configure" msgid="4905518375574791375">"Konfigurasikan"</string>
+ <string name="disconnect" msgid="971412338304200056">"Putuskan sambungan"</string>
+ <string name="session" msgid="6470628549473641030">"Sesi:"</string>
+ <string name="duration" msgid="3584782459928719435">"Tempoh:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Dihantar:"</string>
+ <string name="data_received" msgid="4062776929376067820">"Diterima:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> bait / <xliff:g id="NUMBER_1">%2$s</xliff:g> bingkisan"</string>
+</resources>
diff --git a/packages/VpnDialogs/res/values-nb/strings.xml b/packages/VpnDialogs/res/values-nb/strings.xml
index f716422..6bffc98 100644
--- a/packages/VpnDialogs/res/values-nb/strings.xml
+++ b/packages/VpnDialogs/res/values-nb/strings.xml
@@ -17,8 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> forsøker å etablere en VPN-tilkobling."</string>
- <string name="warning" msgid="5470743576660160079">"Ved å fortsette gir du applikasjonen tillatelse til å fange opp all nettverkstrafikk. "<b>"IKKE godta med mindre du stoler på applikasjonen."</b>" Ellers risikerer du at dataene dine kompromitteres av en ondsinnet programvare."</string>
- <string name="accept" msgid="2889226408765810173">"Jeg stoler på denne applikasjonen."</string>
+ <string name="warning" msgid="5470743576660160079">"Ved å fortsette gir du appen tillatelse til å fange opp all nettverkstrafikk. "<b>"IKKE godta med mindre du stoler på appen."</b>" Ellers risikerer du at dataene dine kompromitteres av en ondsinnet programvare."</string>
+ <string name="accept" msgid="2889226408765810173">"Jeg stoler på denne appen."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN er tilkoblet"</string>
<string name="configure" msgid="4905518375574791375">"Konfigurer"</string>
<string name="disconnect" msgid="971412338304200056">"Koble fra"</string>
diff --git a/packages/VpnDialogs/res/values-zh-rHK/strings.xml b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..8b25d41
--- /dev/null
+++ b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
@@ -0,0 +1,30 @@
+<?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="8359175999006833462">"<xliff:g id="APP">%s</xliff:g> 嘗試建立 VPN 連線。"</string>
+ <string name="warning" msgid="5470743576660160079">"如果繼續進行,即表示您允許該應用程式攔截所有網絡流量。"<b>"除非您信任該應用程式,否則不應接受。"</b>"不然就會讓您的資料陷於遭惡意程式入侵的風險。"</string>
+ <string name="accept" msgid="2889226408765810173">"我信任這個應用程式。"</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN 已連線"</string>
+ <string name="configure" msgid="4905518375574791375">"設定"</string>
+ <string name="disconnect" msgid="971412338304200056">"中斷連線"</string>
+ <string name="session" msgid="6470628549473641030">"時段:"</string>
+ <string name="duration" msgid="3584782459928719435">"持續時間︰"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"已傳送:"</string>
+ <string name="data_received" msgid="4062776929376067820">"已接收:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> 位元組 / <xliff:g id="NUMBER_1">%2$s</xliff:g> 封包"</string>
+</resources>
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
new file mode 100644
index 0000000..09b41fd
--- /dev/null
+++ b/packages/WallpaperCropper/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := telephony-common
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
+LOCAL_PACKAGE_NAME := WallpaperCropper
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/WallpaperCropper/AndroidManifest.xml b/packages/WallpaperCropper/AndroidManifest.xml
new file mode 100644
index 0000000..27755bd
--- /dev/null
+++ b/packages/WallpaperCropper/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wallpapercropper" >
+ <uses-permission android:name="android.permission.SET_WALLPAPER" />
+ <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
+
+ <application android:requiredForAllUsers="true">
+ <activity
+ android:name="WallpaperCropActivity"
+ android:theme="@style/Theme.WallpaperCropper"
+ android:label="@string/crop_wallpaper"
+ android:finishOnCloseSystemDialogs="true">
+ <intent-filter>
+ <action android:name="android.service.wallpaper.CROP_AND_SET_WALLPAPER" />
+ <data android:mimeType="image/*" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/WallpaperCropper/proguard.flags b/packages/WallpaperCropper/proguard.flags
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/WallpaperCropper/proguard.flags
diff --git a/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..53cf687
--- /dev/null
+++ b/packages/WallpaperCropper/res/drawable-hdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..35cda8e
--- /dev/null
+++ b/packages/WallpaperCropper/res/drawable-mdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png b/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png
new file mode 100755
index 0000000..b52dc37
--- /dev/null
+++ b/packages/WallpaperCropper/res/drawable-xhdpi/ic_actionbar_accept.png
Binary files differ
diff --git a/packages/WallpaperCropper/res/layout/actionbar_set_wallpaper.xml b/packages/WallpaperCropper/res/layout/actionbar_set_wallpaper.xml
new file mode 100644
index 0000000..1622742
--- /dev/null
+++ b/packages/WallpaperCropper/res/layout/actionbar_set_wallpaper.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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"
+ style="?android:actionButtonStyle"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <TextView style="?android:actionBarTabTextStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|center_vertical"
+ android:paddingRight="20dp"
+ android:drawableLeft="@drawable/ic_actionbar_accept"
+ android:drawablePadding="8dp"
+ android:gravity="center_vertical"
+ android:text="@string/wallpaper_instructions" />
+</FrameLayout>
diff --git a/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
new file mode 100644
index 0000000..6dc7e35
--- /dev/null
+++ b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wallpaper_cropper"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <com.android.wallpapercropper.CropView
+ android:id="@+id/cropView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <ProgressBar
+ android:id="@+id/loading"
+ style="@android:style/Widget.Holo.ProgressBar.Large"
+ android:visibility="invisible"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminate="true"
+ android:indeterminateOnly="true"
+ android:background="@android:color/transparent" />
+</RelativeLayout>
diff --git a/packages/WallpaperCropper/res/values/strings.xml b/packages/WallpaperCropper/res/values/strings.xml
new file mode 100644
index 0000000..2b8111d
--- /dev/null
+++ b/packages/WallpaperCropper/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="crop_wallpaper">Crop wallpaper</string>
+ <!-- Button label on Wallpaper picker screen; user selects this button to set a specific wallpaper -->
+ <string name="wallpaper_instructions">Set wallpaper</string>
+</resources>
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
new file mode 100644
index 0000000..2b63fe0
--- /dev/null
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -0,0 +1,28 @@
+<?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>
+ <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Holo">
+ <item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowActionBarOverlay">true</item>
+ </style>
+
+ <style name="WallpaperCropperActionBar" parent="android:style/Widget.Holo.ActionBar">
+ <item name="android:displayOptions">showCustom</item>
+ <item name="android:background">#88000000</item>
+ </style>
+</resources>
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java b/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java
new file mode 100644
index 0000000..a671ed2
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.common;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.os.Build;
+import android.util.FloatMath;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class BitmapUtils {
+ private static final String TAG = "BitmapUtils";
+ private static final int DEFAULT_JPEG_QUALITY = 90;
+ public static final int UNCONSTRAINED = -1;
+
+ private BitmapUtils(){}
+
+ /*
+ * Compute the sample size as a function of minSideLength
+ * and maxNumOfPixels.
+ * minSideLength is used to specify that minimal width or height of a
+ * bitmap.
+ * maxNumOfPixels is used to specify the maximal size in pixels that is
+ * tolerable in terms of memory usage.
+ *
+ * The function returns a sample size based on the constraints.
+ * Both size and minSideLength can be passed in as UNCONSTRAINED,
+ * which indicates no care of the corresponding constraint.
+ * The functions prefers returning a sample size that
+ * generates a smaller bitmap, unless minSideLength = UNCONSTRAINED.
+ *
+ * Also, the function rounds up the sample size to a power of 2 or multiple
+ * of 8 because BitmapFactory only honors sample size this way.
+ * For example, BitmapFactory downsamples an image by 2 even though the
+ * request is 3. So we round up the sample size to avoid OOM.
+ */
+ public static int computeSampleSize(int width, int height,
+ int minSideLength, int maxNumOfPixels) {
+ int initialSize = computeInitialSampleSize(
+ width, height, minSideLength, maxNumOfPixels);
+
+ return initialSize <= 8
+ ? Utils.nextPowerOf2(initialSize)
+ : (initialSize + 7) / 8 * 8;
+ }
+
+ private static int computeInitialSampleSize(int w, int h,
+ int minSideLength, int maxNumOfPixels) {
+ if (maxNumOfPixels == UNCONSTRAINED
+ && minSideLength == UNCONSTRAINED) return 1;
+
+ int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
+ (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels));
+
+ if (minSideLength == UNCONSTRAINED) {
+ return lowerBound;
+ } else {
+ int sampleSize = Math.min(w / minSideLength, h / minSideLength);
+ return Math.max(sampleSize, lowerBound);
+ }
+ }
+
+ // This computes a sample size which makes the longer side at least
+ // minSideLength long. If that's not possible, return 1.
+ public static int computeSampleSizeLarger(int w, int h,
+ int minSideLength) {
+ int initialSize = Math.max(w / minSideLength, h / minSideLength);
+ if (initialSize <= 1) return 1;
+
+ return initialSize <= 8
+ ? Utils.prevPowerOf2(initialSize)
+ : initialSize / 8 * 8;
+ }
+
+ // Find the min x that 1 / x >= scale
+ public static int computeSampleSizeLarger(float scale) {
+ int initialSize = (int) FloatMath.floor(1f / scale);
+ if (initialSize <= 1) return 1;
+
+ return initialSize <= 8
+ ? Utils.prevPowerOf2(initialSize)
+ : initialSize / 8 * 8;
+ }
+
+ // Find the max x that 1 / x <= scale.
+ public static int computeSampleSize(float scale) {
+ Utils.assertTrue(scale > 0);
+ int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale));
+ return initialSize <= 8
+ ? Utils.nextPowerOf2(initialSize)
+ : (initialSize + 7) / 8 * 8;
+ }
+
+ public static Bitmap resizeBitmapByScale(
+ Bitmap bitmap, float scale, boolean recycle) {
+ int width = Math.round(bitmap.getWidth() * scale);
+ int height = Math.round(bitmap.getHeight() * scale);
+ if (width == bitmap.getWidth()
+ && height == bitmap.getHeight()) return bitmap;
+ Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
+ Canvas canvas = new Canvas(target);
+ canvas.scale(scale, scale);
+ Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
+ canvas.drawBitmap(bitmap, 0, 0, paint);
+ if (recycle) bitmap.recycle();
+ return target;
+ }
+
+ private static Bitmap.Config getConfig(Bitmap bitmap) {
+ Bitmap.Config config = bitmap.getConfig();
+ if (config == null) {
+ config = Bitmap.Config.ARGB_8888;
+ }
+ return config;
+ }
+
+ public static Bitmap resizeDownBySideLength(
+ Bitmap bitmap, int maxLength, boolean recycle) {
+ int srcWidth = bitmap.getWidth();
+ int srcHeight = bitmap.getHeight();
+ float scale = Math.min(
+ (float) maxLength / srcWidth, (float) maxLength / srcHeight);
+ if (scale >= 1.0f) return bitmap;
+ return resizeBitmapByScale(bitmap, scale, recycle);
+ }
+
+ public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ if (w == size && h == size) return bitmap;
+
+ // scale the image so that the shorter side equals to the target;
+ // the longer side will be center-cropped.
+ float scale = (float) size / Math.min(w, h);
+
+ Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
+ int width = Math.round(scale * bitmap.getWidth());
+ int height = Math.round(scale * bitmap.getHeight());
+ Canvas canvas = new Canvas(target);
+ canvas.translate((size - width) / 2f, (size - height) / 2f);
+ canvas.scale(scale, scale);
+ Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
+ canvas.drawBitmap(bitmap, 0, 0, paint);
+ if (recycle) bitmap.recycle();
+ return target;
+ }
+
+ public static void recycleSilently(Bitmap bitmap) {
+ if (bitmap == null) return;
+ try {
+ bitmap.recycle();
+ } catch (Throwable t) {
+ Log.w(TAG, "unable recycle bitmap", t);
+ }
+ }
+
+ public static Bitmap rotateBitmap(Bitmap source, int rotation, boolean recycle) {
+ if (rotation == 0) return source;
+ int w = source.getWidth();
+ int h = source.getHeight();
+ Matrix m = new Matrix();
+ m.postRotate(rotation);
+ Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, w, h, m, true);
+ if (recycle) source.recycle();
+ return bitmap;
+ }
+
+ public static Bitmap createVideoThumbnail(String filePath) {
+ // MediaMetadataRetriever is available on API Level 8
+ // but is hidden until API Level 10
+ Class<?> clazz = null;
+ Object instance = null;
+ try {
+ clazz = Class.forName("android.media.MediaMetadataRetriever");
+ instance = clazz.newInstance();
+
+ Method method = clazz.getMethod("setDataSource", String.class);
+ method.invoke(instance, filePath);
+
+ // The method name changes between API Level 9 and 10.
+ if (Build.VERSION.SDK_INT <= 9) {
+ return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
+ } else {
+ byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
+ if (data != null) {
+ Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
+ if (bitmap != null) return bitmap;
+ }
+ return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
+ }
+ } catch (IllegalArgumentException ex) {
+ // Assume this is a corrupt video file
+ } catch (RuntimeException ex) {
+ // Assume this is a corrupt video file.
+ } catch (InstantiationException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } catch (ClassNotFoundException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "createVideoThumbnail", e);
+ } finally {
+ try {
+ if (instance != null) {
+ clazz.getMethod("release").invoke(instance);
+ }
+ } catch (Exception ignored) {
+ }
+ }
+ return null;
+ }
+
+ public static byte[] compressToBytes(Bitmap bitmap) {
+ return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY);
+ }
+
+ public static byte[] compressToBytes(Bitmap bitmap, int quality) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(65536);
+ bitmap.compress(CompressFormat.JPEG, quality, baos);
+ return baos.toByteArray();
+ }
+
+ public static boolean isSupportedByRegionDecoder(String mimeType) {
+ if (mimeType == null) return false;
+ mimeType = mimeType.toLowerCase();
+ return mimeType.startsWith("image/") &&
+ (!mimeType.equals("image/gif") && !mimeType.endsWith("bmp"));
+ }
+
+ public static boolean isRotationSupported(String mimeType) {
+ if (mimeType == null) return false;
+ mimeType = mimeType.toLowerCase();
+ return mimeType.equals("image/jpeg");
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/common/Utils.java b/packages/WallpaperCropper/src/com/android/gallery3d/common/Utils.java
new file mode 100644
index 0000000..614a081
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/common/Utils.java
@@ -0,0 +1,340 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.common;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.Cursor;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+public class Utils {
+ private static final String TAG = "Utils";
+ private static final String DEBUG_TAG = "GalleryDebug";
+
+ private static final long POLY64REV = 0x95AC9329AC4BC9B5L;
+ private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL;
+
+ private static long[] sCrcTable = new long[256];
+
+ private static final boolean IS_DEBUG_BUILD =
+ Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug");
+
+ private static final String MASK_STRING = "********************************";
+
+ // Throws AssertionError if the input is false.
+ public static void assertTrue(boolean cond) {
+ if (!cond) {
+ throw new AssertionError();
+ }
+ }
+
+ // Throws AssertionError with the message. We had a method having the form
+ // assertTrue(boolean cond, String message, Object ... args);
+ // However a call to that method will cause memory allocation even if the
+ // condition is false (due to autoboxing generated by "Object ... args"),
+ // so we don't use that anymore.
+ public static void fail(String message, Object ... args) {
+ throw new AssertionError(
+ args.length == 0 ? message : String.format(message, args));
+ }
+
+ // Throws NullPointerException if the input is null.
+ public static <T> T checkNotNull(T object) {
+ if (object == null) throw new NullPointerException();
+ return object;
+ }
+
+ // Returns true if two input Object are both null or equal
+ // to each other.
+ public static boolean equals(Object a, Object b) {
+ return (a == b) || (a == null ? false : a.equals(b));
+ }
+
+ // Returns the next power of two.
+ // Returns the input if it is already power of 2.
+ // Throws IllegalArgumentException if the input is <= 0 or
+ // the answer overflows.
+ public static int nextPowerOf2(int n) {
+ if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException("n is invalid: " + n);
+ n -= 1;
+ n |= n >> 16;
+ n |= n >> 8;
+ n |= n >> 4;
+ n |= n >> 2;
+ n |= n >> 1;
+ return n + 1;
+ }
+
+ // Returns the previous power of two.
+ // Returns the input if it is already power of 2.
+ // Throws IllegalArgumentException if the input is <= 0
+ public static int prevPowerOf2(int n) {
+ if (n <= 0) throw new IllegalArgumentException();
+ return Integer.highestOneBit(n);
+ }
+
+ // Returns the input value x clamped to the range [min, max].
+ public static int clamp(int x, int min, int max) {
+ if (x > max) return max;
+ if (x < min) return min;
+ return x;
+ }
+
+ // Returns the input value x clamped to the range [min, max].
+ public static float clamp(float x, float min, float max) {
+ if (x > max) return max;
+ if (x < min) return min;
+ return x;
+ }
+
+ // Returns the input value x clamped to the range [min, max].
+ public static long clamp(long x, long min, long max) {
+ if (x > max) return max;
+ if (x < min) return min;
+ return x;
+ }
+
+ public static boolean isOpaque(int color) {
+ return color >>> 24 == 0xFF;
+ }
+
+ public static void swap(int[] array, int i, int j) {
+ int temp = array[i];
+ array[i] = array[j];
+ array[j] = temp;
+ }
+
+ /**
+ * A function thats returns a 64-bit crc for string
+ *
+ * @param in input string
+ * @return a 64-bit crc value
+ */
+ public static final long crc64Long(String in) {
+ if (in == null || in.length() == 0) {
+ return 0;
+ }
+ return crc64Long(getBytes(in));
+ }
+
+ static {
+ // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c
+ long part;
+ for (int i = 0; i < 256; i++) {
+ part = i;
+ for (int j = 0; j < 8; j++) {
+ long x = ((int) part & 1) != 0 ? POLY64REV : 0;
+ part = (part >> 1) ^ x;
+ }
+ sCrcTable[i] = part;
+ }
+ }
+
+ public static final long crc64Long(byte[] buffer) {
+ long crc = INITIALCRC;
+ for (int k = 0, n = buffer.length; k < n; ++k) {
+ crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8);
+ }
+ return crc;
+ }
+
+ public static byte[] getBytes(String in) {
+ byte[] result = new byte[in.length() * 2];
+ int output = 0;
+ for (char ch : in.toCharArray()) {
+ result[output++] = (byte) (ch & 0xFF);
+ result[output++] = (byte) (ch >> 8);
+ }
+ return result;
+ }
+
+ public static void closeSilently(Closeable c) {
+ if (c == null) return;
+ try {
+ c.close();
+ } catch (IOException t) {
+ Log.w(TAG, "close fail ", t);
+ }
+ }
+
+ public static int compare(long a, long b) {
+ return a < b ? -1 : a == b ? 0 : 1;
+ }
+
+ public static int ceilLog2(float value) {
+ int i;
+ for (i = 0; i < 31; i++) {
+ if ((1 << i) >= value) break;
+ }
+ return i;
+ }
+
+ public static int floorLog2(float value) {
+ int i;
+ for (i = 0; i < 31; i++) {
+ if ((1 << i) > value) break;
+ }
+ return i - 1;
+ }
+
+ public static void closeSilently(ParcelFileDescriptor fd) {
+ try {
+ if (fd != null) fd.close();
+ } catch (Throwable t) {
+ Log.w(TAG, "fail to close", t);
+ }
+ }
+
+ public static void closeSilently(Cursor cursor) {
+ try {
+ if (cursor != null) cursor.close();
+ } catch (Throwable t) {
+ Log.w(TAG, "fail to close", t);
+ }
+ }
+
+ public static float interpolateAngle(
+ float source, float target, float progress) {
+ // interpolate the angle from source to target
+ // We make the difference in the range of [-179, 180], this is the
+ // shortest path to change source to target.
+ float diff = target - source;
+ if (diff < 0) diff += 360f;
+ if (diff > 180) diff -= 360f;
+
+ float result = source + diff * progress;
+ return result < 0 ? result + 360f : result;
+ }
+
+ public static float interpolateScale(
+ float source, float target, float progress) {
+ return source + progress * (target - source);
+ }
+
+ public static String ensureNotNull(String value) {
+ return value == null ? "" : value;
+ }
+
+ public static float parseFloatSafely(String content, float defaultValue) {
+ if (content == null) return defaultValue;
+ try {
+ return Float.parseFloat(content);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ public static int parseIntSafely(String content, int defaultValue) {
+ if (content == null) return defaultValue;
+ try {
+ return Integer.parseInt(content);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ public static boolean isNullOrEmpty(String exifMake) {
+ return TextUtils.isEmpty(exifMake);
+ }
+
+ public static void waitWithoutInterrupt(Object object) {
+ try {
+ object.wait();
+ } catch (InterruptedException e) {
+ Log.w(TAG, "unexpected interrupt: " + object);
+ }
+ }
+
+ public static boolean handleInterrruptedException(Throwable e) {
+ // A helper to deal with the interrupt exception
+ // If an interrupt detected, we will setup the bit again.
+ if (e instanceof InterruptedIOException
+ || e instanceof InterruptedException) {
+ Thread.currentThread().interrupt();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return String with special XML characters escaped.
+ */
+ public static String escapeXml(String s) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0, len = s.length(); i < len; ++i) {
+ char c = s.charAt(i);
+ switch (c) {
+ case '<': sb.append("<"); break;
+ case '>': sb.append(">"); break;
+ case '\"': sb.append("""); break;
+ case '\'': sb.append("'"); break;
+ case '&': sb.append("&"); break;
+ default: sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ public static String getUserAgent(Context context) {
+ PackageInfo packageInfo;
+ try {
+ packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ } catch (NameNotFoundException e) {
+ throw new IllegalStateException("getPackageInfo failed");
+ }
+ return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s",
+ packageInfo.packageName,
+ packageInfo.versionName,
+ Build.BRAND,
+ Build.DEVICE,
+ Build.MODEL,
+ Build.ID,
+ Build.VERSION.SDK_INT,
+ Build.VERSION.RELEASE,
+ Build.VERSION.INCREMENTAL);
+ }
+
+ public static String[] copyOf(String[] source, int newSize) {
+ String[] result = new String[newSize];
+ newSize = Math.min(source.length, newSize);
+ System.arraycopy(source, 0, result, 0, newSize);
+ return result;
+ }
+
+ // Mask information for debugging only. It returns <code>info.toString()</code> directly
+ // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask ("****")
+ // in release build to protect the information (e.g. for privacy issue).
+ public static String maskDebugInfo(Object info) {
+ if (info == null) return null;
+ String s = info.toString();
+ int length = Math.min(s.length(), MASK_STRING.length());
+ return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length);
+ }
+
+ // This method should be ONLY used for debugging.
+ public static void debug(String message, Object ... args) {
+ Log.v(DEBUG_TAG, String.format(message, args));
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ByteBufferInputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ByteBufferInputStream.java
new file mode 100644
index 0000000..7fb9f22
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ByteBufferInputStream.java
@@ -0,0 +1,48 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+class ByteBufferInputStream extends InputStream {
+
+ private ByteBuffer mBuf;
+
+ public ByteBufferInputStream(ByteBuffer buf) {
+ mBuf = buf;
+ }
+
+ @Override
+ public int read() {
+ if (!mBuf.hasRemaining()) {
+ return -1;
+ }
+ return mBuf.get() & 0xFF;
+ }
+
+ @Override
+ public int read(byte[] bytes, int off, int len) {
+ if (!mBuf.hasRemaining()) {
+ return -1;
+ }
+
+ len = Math.min(len, mBuf.remaining());
+ mBuf.get(bytes, off, len);
+ return len;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/CountedDataInputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/CountedDataInputStream.java
new file mode 100644
index 0000000..dfd4a1a
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/CountedDataInputStream.java
@@ -0,0 +1,136 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+class CountedDataInputStream extends FilterInputStream {
+
+ private int mCount = 0;
+
+ // allocate a byte buffer for a long value;
+ private final byte mByteArray[] = new byte[8];
+ private final ByteBuffer mByteBuffer = ByteBuffer.wrap(mByteArray);
+
+ protected CountedDataInputStream(InputStream in) {
+ super(in);
+ }
+
+ public int getReadByteCount() {
+ return mCount;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ int r = in.read(b);
+ mCount += (r >= 0) ? r : 0;
+ return r;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int r = in.read(b, off, len);
+ mCount += (r >= 0) ? r : 0;
+ return r;
+ }
+
+ @Override
+ public int read() throws IOException {
+ int r = in.read();
+ mCount += (r >= 0) ? 1 : 0;
+ return r;
+ }
+
+ @Override
+ public long skip(long length) throws IOException {
+ long skip = in.skip(length);
+ mCount += skip;
+ return skip;
+ }
+
+ public void skipOrThrow(long length) throws IOException {
+ if (skip(length) != length) throw new EOFException();
+ }
+
+ public void skipTo(long target) throws IOException {
+ long cur = mCount;
+ long diff = target - cur;
+ assert(diff >= 0);
+ skipOrThrow(diff);
+ }
+
+ public void readOrThrow(byte[] b, int off, int len) throws IOException {
+ int r = read(b, off, len);
+ if (r != len) throw new EOFException();
+ }
+
+ public void readOrThrow(byte[] b) throws IOException {
+ readOrThrow(b, 0, b.length);
+ }
+
+ public void setByteOrder(ByteOrder order) {
+ mByteBuffer.order(order);
+ }
+
+ public ByteOrder getByteOrder() {
+ return mByteBuffer.order();
+ }
+
+ public short readShort() throws IOException {
+ readOrThrow(mByteArray, 0 ,2);
+ mByteBuffer.rewind();
+ return mByteBuffer.getShort();
+ }
+
+ public int readUnsignedShort() throws IOException {
+ return readShort() & 0xffff;
+ }
+
+ public int readInt() throws IOException {
+ readOrThrow(mByteArray, 0 , 4);
+ mByteBuffer.rewind();
+ return mByteBuffer.getInt();
+ }
+
+ public long readUnsignedInt() throws IOException {
+ return readInt() & 0xffffffffL;
+ }
+
+ public long readLong() throws IOException {
+ readOrThrow(mByteArray, 0 , 8);
+ mByteBuffer.rewind();
+ return mByteBuffer.getLong();
+ }
+
+ public String readString(int n) throws IOException {
+ byte buf[] = new byte[n];
+ readOrThrow(buf);
+ return new String(buf, "UTF8");
+ }
+
+ public String readString(int n, Charset charset) throws IOException {
+ byte buf[] = new byte[n];
+ readOrThrow(buf);
+ return new String(buf, charset);
+ }
+}
\ No newline at end of file
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java
new file mode 100644
index 0000000..8422382
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifData.java
@@ -0,0 +1,348 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This class stores the EXIF header in IFDs according to the JPEG
+ * specification. It is the result produced by {@link ExifReader}.
+ *
+ * @see ExifReader
+ * @see IfdData
+ */
+class ExifData {
+ private static final String TAG = "ExifData";
+ private static final byte[] USER_COMMENT_ASCII = {
+ 0x41, 0x53, 0x43, 0x49, 0x49, 0x00, 0x00, 0x00
+ };
+ private static final byte[] USER_COMMENT_JIS = {
+ 0x4A, 0x49, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ private static final byte[] USER_COMMENT_UNICODE = {
+ 0x55, 0x4E, 0x49, 0x43, 0x4F, 0x44, 0x45, 0x00
+ };
+
+ private final IfdData[] mIfdDatas = new IfdData[IfdId.TYPE_IFD_COUNT];
+ private byte[] mThumbnail;
+ private ArrayList<byte[]> mStripBytes = new ArrayList<byte[]>();
+ private final ByteOrder mByteOrder;
+
+ ExifData(ByteOrder order) {
+ mByteOrder = order;
+ }
+
+ /**
+ * Gets the compressed thumbnail. Returns null if there is no compressed
+ * thumbnail.
+ *
+ * @see #hasCompressedThumbnail()
+ */
+ protected byte[] getCompressedThumbnail() {
+ return mThumbnail;
+ }
+
+ /**
+ * Sets the compressed thumbnail.
+ */
+ protected void setCompressedThumbnail(byte[] thumbnail) {
+ mThumbnail = thumbnail;
+ }
+
+ /**
+ * Returns true it this header contains a compressed thumbnail.
+ */
+ protected boolean hasCompressedThumbnail() {
+ return mThumbnail != null;
+ }
+
+ /**
+ * Adds an uncompressed strip.
+ */
+ protected void setStripBytes(int index, byte[] strip) {
+ if (index < mStripBytes.size()) {
+ mStripBytes.set(index, strip);
+ } else {
+ for (int i = mStripBytes.size(); i < index; i++) {
+ mStripBytes.add(null);
+ }
+ mStripBytes.add(strip);
+ }
+ }
+
+ /**
+ * Gets the strip count.
+ */
+ protected int getStripCount() {
+ return mStripBytes.size();
+ }
+
+ /**
+ * Gets the strip at the specified index.
+ *
+ * @exceptions #IndexOutOfBoundException
+ */
+ protected byte[] getStrip(int index) {
+ return mStripBytes.get(index);
+ }
+
+ /**
+ * Returns true if this header contains uncompressed strip.
+ */
+ protected boolean hasUncompressedStrip() {
+ return mStripBytes.size() != 0;
+ }
+
+ /**
+ * Gets the byte order.
+ */
+ protected ByteOrder getByteOrder() {
+ return mByteOrder;
+ }
+
+ /**
+ * Returns the {@link IfdData} object corresponding to a given IFD if it
+ * exists or null.
+ */
+ protected IfdData getIfdData(int ifdId) {
+ if (ExifTag.isValidIfd(ifdId)) {
+ return mIfdDatas[ifdId];
+ }
+ return null;
+ }
+
+ /**
+ * Adds IFD data. If IFD data of the same type already exists, it will be
+ * replaced by the new data.
+ */
+ protected void addIfdData(IfdData data) {
+ mIfdDatas[data.getId()] = data;
+ }
+
+ /**
+ * Returns the {@link IfdData} object corresponding to a given IFD or
+ * generates one if none exist.
+ */
+ protected IfdData getOrCreateIfdData(int ifdId) {
+ IfdData ifdData = mIfdDatas[ifdId];
+ if (ifdData == null) {
+ ifdData = new IfdData(ifdId);
+ mIfdDatas[ifdId] = ifdData;
+ }
+ return ifdData;
+ }
+
+ /**
+ * Returns the tag with a given TID in the given IFD if the tag exists.
+ * Otherwise returns null.
+ */
+ protected ExifTag getTag(short tag, int ifd) {
+ IfdData ifdData = mIfdDatas[ifd];
+ return (ifdData == null) ? null : ifdData.getTag(tag);
+ }
+
+ /**
+ * Adds the given ExifTag to its default IFD and returns an existing ExifTag
+ * with the same TID or null if none exist.
+ */
+ protected ExifTag addTag(ExifTag tag) {
+ if (tag != null) {
+ int ifd = tag.getIfd();
+ return addTag(tag, ifd);
+ }
+ return null;
+ }
+
+ /**
+ * Adds the given ExifTag to the given IFD and returns an existing ExifTag
+ * with the same TID or null if none exist.
+ */
+ protected ExifTag addTag(ExifTag tag, int ifdId) {
+ if (tag != null && ExifTag.isValidIfd(ifdId)) {
+ IfdData ifdData = getOrCreateIfdData(ifdId);
+ return ifdData.setTag(tag);
+ }
+ return null;
+ }
+
+ protected void clearThumbnailAndStrips() {
+ mThumbnail = null;
+ mStripBytes.clear();
+ }
+
+ /**
+ * Removes the thumbnail and its related tags. IFD1 will be removed.
+ */
+ protected void removeThumbnailData() {
+ clearThumbnailAndStrips();
+ mIfdDatas[IfdId.TYPE_IFD_1] = null;
+ }
+
+ /**
+ * Removes the tag with a given TID and IFD.
+ */
+ protected void removeTag(short tagId, int ifdId) {
+ IfdData ifdData = mIfdDatas[ifdId];
+ if (ifdData == null) {
+ return;
+ }
+ ifdData.removeTag(tagId);
+ }
+
+ /**
+ * Decodes the user comment tag into string as specified in the EXIF
+ * standard. Returns null if decoding failed.
+ */
+ protected String getUserComment() {
+ IfdData ifdData = mIfdDatas[IfdId.TYPE_IFD_0];
+ if (ifdData == null) {
+ return null;
+ }
+ ExifTag tag = ifdData.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_USER_COMMENT));
+ if (tag == null) {
+ return null;
+ }
+ if (tag.getComponentCount() < 8) {
+ return null;
+ }
+
+ byte[] buf = new byte[tag.getComponentCount()];
+ tag.getBytes(buf);
+
+ byte[] code = new byte[8];
+ System.arraycopy(buf, 0, code, 0, 8);
+
+ try {
+ if (Arrays.equals(code, USER_COMMENT_ASCII)) {
+ return new String(buf, 8, buf.length - 8, "US-ASCII");
+ } else if (Arrays.equals(code, USER_COMMENT_JIS)) {
+ return new String(buf, 8, buf.length - 8, "EUC-JP");
+ } else if (Arrays.equals(code, USER_COMMENT_UNICODE)) {
+ return new String(buf, 8, buf.length - 8, "UTF-16");
+ } else {
+ return null;
+ }
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, "Failed to decode the user comment");
+ return null;
+ }
+ }
+
+ /**
+ * Returns a list of all {@link ExifTag}s in the ExifData or null if there
+ * are none.
+ */
+ protected List<ExifTag> getAllTags() {
+ ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
+ for (IfdData d : mIfdDatas) {
+ if (d != null) {
+ ExifTag[] tags = d.getAllTags();
+ if (tags != null) {
+ for (ExifTag t : tags) {
+ ret.add(t);
+ }
+ }
+ }
+ }
+ if (ret.size() == 0) {
+ return null;
+ }
+ return ret;
+ }
+
+ /**
+ * Returns a list of all {@link ExifTag}s in a given IFD or null if there
+ * are none.
+ */
+ protected List<ExifTag> getAllTagsForIfd(int ifd) {
+ IfdData d = mIfdDatas[ifd];
+ if (d == null) {
+ return null;
+ }
+ ExifTag[] tags = d.getAllTags();
+ if (tags == null) {
+ return null;
+ }
+ ArrayList<ExifTag> ret = new ArrayList<ExifTag>(tags.length);
+ for (ExifTag t : tags) {
+ ret.add(t);
+ }
+ if (ret.size() == 0) {
+ return null;
+ }
+ return ret;
+ }
+
+ /**
+ * Returns a list of all {@link ExifTag}s with a given TID or null if there
+ * are none.
+ */
+ protected List<ExifTag> getAllTagsForTagId(short tag) {
+ ArrayList<ExifTag> ret = new ArrayList<ExifTag>();
+ for (IfdData d : mIfdDatas) {
+ if (d != null) {
+ ExifTag t = d.getTag(tag);
+ if (t != null) {
+ ret.add(t);
+ }
+ }
+ }
+ if (ret.size() == 0) {
+ return null;
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof ExifData) {
+ ExifData data = (ExifData) obj;
+ if (data.mByteOrder != mByteOrder ||
+ data.mStripBytes.size() != mStripBytes.size() ||
+ !Arrays.equals(data.mThumbnail, mThumbnail)) {
+ return false;
+ }
+ for (int i = 0; i < mStripBytes.size(); i++) {
+ if (!Arrays.equals(data.mStripBytes.get(i), mStripBytes.get(i))) {
+ return false;
+ }
+ }
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ IfdData ifd1 = data.getIfdData(i);
+ IfdData ifd2 = getIfdData(i);
+ if (ifd1 != ifd2 && ifd1 != null && !ifd1.equals(ifd2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInterface.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInterface.java
new file mode 100644
index 0000000..a1cf0fc
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInterface.java
@@ -0,0 +1,2407 @@
+/*
+ * 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.gallery3d.exif;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.SparseIntArray;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+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.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel.MapMode;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.TimeZone;
+
+/**
+ * This class provides methods and constants for reading and writing jpeg file
+ * metadata. It contains a collection of ExifTags, and a collection of
+ * definitions for creating valid ExifTags. The collection of ExifTags can be
+ * updated by: reading new ones from a file, deleting or adding existing ones,
+ * or building new ExifTags from a tag definition. These ExifTags can be written
+ * to a valid jpeg image as exif metadata.
+ * <p>
+ * Each ExifTag has a tag ID (TID) and is stored in a specific image file
+ * directory (IFD) as specified by the exif standard. A tag definition can be
+ * looked up with a constant that is a combination of TID and IFD. This
+ * definition has information about the type, number of components, and valid
+ * IFDs for a tag.
+ *
+ * @see ExifTag
+ */
+public class ExifInterface {
+ public static final int TAG_NULL = -1;
+ public static final int IFD_NULL = -1;
+ public static final int DEFINITION_NULL = 0;
+
+ /**
+ * Tag constants for Jeita EXIF 2.2
+ */
+
+ // IFD 0
+ public static final int TAG_IMAGE_WIDTH =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0100);
+ public static final int TAG_IMAGE_LENGTH =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0101); // Image height
+ public static final int TAG_BITS_PER_SAMPLE =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0102);
+ public static final int TAG_COMPRESSION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0103);
+ public static final int TAG_PHOTOMETRIC_INTERPRETATION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0106);
+ public static final int TAG_IMAGE_DESCRIPTION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x010E);
+ public static final int TAG_MAKE =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x010F);
+ public static final int TAG_MODEL =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0110);
+ public static final int TAG_STRIP_OFFSETS =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0111);
+ public static final int TAG_ORIENTATION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0112);
+ public static final int TAG_SAMPLES_PER_PIXEL =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0115);
+ public static final int TAG_ROWS_PER_STRIP =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0116);
+ public static final int TAG_STRIP_BYTE_COUNTS =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0117);
+ public static final int TAG_X_RESOLUTION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x011A);
+ public static final int TAG_Y_RESOLUTION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x011B);
+ public static final int TAG_PLANAR_CONFIGURATION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x011C);
+ public static final int TAG_RESOLUTION_UNIT =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0128);
+ public static final int TAG_TRANSFER_FUNCTION =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x012D);
+ public static final int TAG_SOFTWARE =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0131);
+ public static final int TAG_DATE_TIME =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0132);
+ public static final int TAG_ARTIST =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x013B);
+ public static final int TAG_WHITE_POINT =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x013E);
+ public static final int TAG_PRIMARY_CHROMATICITIES =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x013F);
+ public static final int TAG_Y_CB_CR_COEFFICIENTS =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0211);
+ public static final int TAG_Y_CB_CR_SUB_SAMPLING =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0212);
+ public static final int TAG_Y_CB_CR_POSITIONING =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0213);
+ public static final int TAG_REFERENCE_BLACK_WHITE =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x0214);
+ public static final int TAG_COPYRIGHT =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x8298);
+ public static final int TAG_EXIF_IFD =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x8769);
+ public static final int TAG_GPS_IFD =
+ defineTag(IfdId.TYPE_IFD_0, (short) 0x8825);
+ // IFD 1
+ public static final int TAG_JPEG_INTERCHANGE_FORMAT =
+ defineTag(IfdId.TYPE_IFD_1, (short) 0x0201);
+ public static final int TAG_JPEG_INTERCHANGE_FORMAT_LENGTH =
+ defineTag(IfdId.TYPE_IFD_1, (short) 0x0202);
+ // IFD Exif Tags
+ public static final int TAG_EXPOSURE_TIME =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829A);
+ public static final int TAG_F_NUMBER =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x829D);
+ public static final int TAG_EXPOSURE_PROGRAM =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8822);
+ public static final int TAG_SPECTRAL_SENSITIVITY =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8824);
+ public static final int TAG_ISO_SPEED_RATINGS =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8827);
+ public static final int TAG_OECF =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x8828);
+ public static final int TAG_EXIF_VERSION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9000);
+ public static final int TAG_DATE_TIME_ORIGINAL =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9003);
+ public static final int TAG_DATE_TIME_DIGITIZED =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9004);
+ public static final int TAG_COMPONENTS_CONFIGURATION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9101);
+ public static final int TAG_COMPRESSED_BITS_PER_PIXEL =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9102);
+ public static final int TAG_SHUTTER_SPEED_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9201);
+ public static final int TAG_APERTURE_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9202);
+ public static final int TAG_BRIGHTNESS_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9203);
+ public static final int TAG_EXPOSURE_BIAS_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9204);
+ public static final int TAG_MAX_APERTURE_VALUE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9205);
+ public static final int TAG_SUBJECT_DISTANCE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9206);
+ public static final int TAG_METERING_MODE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9207);
+ public static final int TAG_LIGHT_SOURCE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9208);
+ public static final int TAG_FLASH =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9209);
+ public static final int TAG_FOCAL_LENGTH =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x920A);
+ public static final int TAG_SUBJECT_AREA =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9214);
+ public static final int TAG_MAKER_NOTE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x927C);
+ public static final int TAG_USER_COMMENT =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9286);
+ public static final int TAG_SUB_SEC_TIME =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9290);
+ public static final int TAG_SUB_SEC_TIME_ORIGINAL =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9291);
+ public static final int TAG_SUB_SEC_TIME_DIGITIZED =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0x9292);
+ public static final int TAG_FLASHPIX_VERSION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA000);
+ public static final int TAG_COLOR_SPACE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA001);
+ public static final int TAG_PIXEL_X_DIMENSION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA002);
+ public static final int TAG_PIXEL_Y_DIMENSION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA003);
+ public static final int TAG_RELATED_SOUND_FILE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA004);
+ public static final int TAG_INTEROPERABILITY_IFD =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA005);
+ public static final int TAG_FLASH_ENERGY =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20B);
+ public static final int TAG_SPATIAL_FREQUENCY_RESPONSE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20C);
+ public static final int TAG_FOCAL_PLANE_X_RESOLUTION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20E);
+ public static final int TAG_FOCAL_PLANE_Y_RESOLUTION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA20F);
+ public static final int TAG_FOCAL_PLANE_RESOLUTION_UNIT =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA210);
+ public static final int TAG_SUBJECT_LOCATION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA214);
+ public static final int TAG_EXPOSURE_INDEX =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA215);
+ public static final int TAG_SENSING_METHOD =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA217);
+ public static final int TAG_FILE_SOURCE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA300);
+ public static final int TAG_SCENE_TYPE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA301);
+ public static final int TAG_CFA_PATTERN =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA302);
+ public static final int TAG_CUSTOM_RENDERED =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA401);
+ public static final int TAG_EXPOSURE_MODE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA402);
+ public static final int TAG_WHITE_BALANCE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA403);
+ public static final int TAG_DIGITAL_ZOOM_RATIO =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA404);
+ public static final int TAG_FOCAL_LENGTH_IN_35_MM_FILE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA405);
+ public static final int TAG_SCENE_CAPTURE_TYPE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA406);
+ public static final int TAG_GAIN_CONTROL =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA407);
+ public static final int TAG_CONTRAST =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA408);
+ public static final int TAG_SATURATION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA409);
+ public static final int TAG_SHARPNESS =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40A);
+ public static final int TAG_DEVICE_SETTING_DESCRIPTION =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40B);
+ public static final int TAG_SUBJECT_DISTANCE_RANGE =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA40C);
+ public static final int TAG_IMAGE_UNIQUE_ID =
+ defineTag(IfdId.TYPE_IFD_EXIF, (short) 0xA420);
+ // IFD GPS tags
+ public static final int TAG_GPS_VERSION_ID =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 0);
+ public static final int TAG_GPS_LATITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 1);
+ public static final int TAG_GPS_LATITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 2);
+ public static final int TAG_GPS_LONGITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 3);
+ public static final int TAG_GPS_LONGITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 4);
+ public static final int TAG_GPS_ALTITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 5);
+ public static final int TAG_GPS_ALTITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 6);
+ public static final int TAG_GPS_TIME_STAMP =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 7);
+ public static final int TAG_GPS_SATTELLITES =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 8);
+ public static final int TAG_GPS_STATUS =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 9);
+ public static final int TAG_GPS_MEASURE_MODE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 10);
+ public static final int TAG_GPS_DOP =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 11);
+ public static final int TAG_GPS_SPEED_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 12);
+ public static final int TAG_GPS_SPEED =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 13);
+ public static final int TAG_GPS_TRACK_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 14);
+ public static final int TAG_GPS_TRACK =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 15);
+ public static final int TAG_GPS_IMG_DIRECTION_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 16);
+ public static final int TAG_GPS_IMG_DIRECTION =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 17);
+ public static final int TAG_GPS_MAP_DATUM =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 18);
+ public static final int TAG_GPS_DEST_LATITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 19);
+ public static final int TAG_GPS_DEST_LATITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 20);
+ public static final int TAG_GPS_DEST_LONGITUDE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 21);
+ public static final int TAG_GPS_DEST_LONGITUDE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 22);
+ public static final int TAG_GPS_DEST_BEARING_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 23);
+ public static final int TAG_GPS_DEST_BEARING =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 24);
+ public static final int TAG_GPS_DEST_DISTANCE_REF =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 25);
+ public static final int TAG_GPS_DEST_DISTANCE =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 26);
+ public static final int TAG_GPS_PROCESSING_METHOD =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 27);
+ public static final int TAG_GPS_AREA_INFORMATION =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 28);
+ public static final int TAG_GPS_DATE_STAMP =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 29);
+ public static final int TAG_GPS_DIFFERENTIAL =
+ defineTag(IfdId.TYPE_IFD_GPS, (short) 30);
+ // IFD Interoperability tags
+ public static final int TAG_INTEROPERABILITY_INDEX =
+ defineTag(IfdId.TYPE_IFD_INTEROPERABILITY, (short) 1);
+
+ /**
+ * Tags that contain offset markers. These are included in the banned
+ * defines.
+ */
+ private static HashSet<Short> sOffsetTags = new HashSet<Short>();
+ static {
+ sOffsetTags.add(getTrueTagKey(TAG_GPS_IFD));
+ sOffsetTags.add(getTrueTagKey(TAG_EXIF_IFD));
+ sOffsetTags.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT));
+ sOffsetTags.add(getTrueTagKey(TAG_INTEROPERABILITY_IFD));
+ sOffsetTags.add(getTrueTagKey(TAG_STRIP_OFFSETS));
+ }
+
+ /**
+ * Tags with definitions that cannot be overridden (banned defines).
+ */
+ protected static HashSet<Short> sBannedDefines = new HashSet<Short>(sOffsetTags);
+ static {
+ sBannedDefines.add(getTrueTagKey(TAG_NULL));
+ sBannedDefines.add(getTrueTagKey(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
+ sBannedDefines.add(getTrueTagKey(TAG_STRIP_BYTE_COUNTS));
+ }
+
+ /**
+ * Returns the constant representing a tag with a given TID and default IFD.
+ */
+ public static int defineTag(int ifdId, short tagId) {
+ return (tagId & 0x0000ffff) | (ifdId << 16);
+ }
+
+ /**
+ * Returns the TID for a tag constant.
+ */
+ public static short getTrueTagKey(int tag) {
+ // Truncate
+ return (short) tag;
+ }
+
+ /**
+ * Returns the default IFD for a tag constant.
+ */
+ public static int getTrueIfd(int tag) {
+ return tag >>> 16;
+ }
+
+ /**
+ * Constants for {@link TAG_ORIENTATION}. They can be interpreted as
+ * follows:
+ * <ul>
+ * <li>TOP_LEFT is the normal orientation.</li>
+ * <li>TOP_RIGHT is a left-right mirror.</li>
+ * <li>BOTTOM_LEFT is a 180 degree rotation.</li>
+ * <li>BOTTOM_RIGHT is a top-bottom mirror.</li>
+ * <li>LEFT_TOP is mirrored about the top-left<->bottom-right axis.</li>
+ * <li>RIGHT_TOP is a 90 degree clockwise rotation.</li>
+ * <li>LEFT_BOTTOM is mirrored about the top-right<->bottom-left axis.</li>
+ * <li>RIGHT_BOTTOM is a 270 degree clockwise rotation.</li>
+ * </ul>
+ */
+ public static interface Orientation {
+ public static final short TOP_LEFT = 1;
+ public static final short TOP_RIGHT = 2;
+ public static final short BOTTOM_LEFT = 3;
+ public static final short BOTTOM_RIGHT = 4;
+ public static final short LEFT_TOP = 5;
+ public static final short RIGHT_TOP = 6;
+ public static final short LEFT_BOTTOM = 7;
+ public static final short RIGHT_BOTTOM = 8;
+ }
+
+ /**
+ * Constants for {@link TAG_Y_CB_CR_POSITIONING}
+ */
+ public static interface YCbCrPositioning {
+ public static final short CENTERED = 1;
+ public static final short CO_SITED = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_COMPRESSION}
+ */
+ public static interface Compression {
+ public static final short UNCOMPRESSION = 1;
+ public static final short JPEG = 6;
+ }
+
+ /**
+ * Constants for {@link TAG_RESOLUTION_UNIT}
+ */
+ public static interface ResolutionUnit {
+ public static final short INCHES = 2;
+ public static final short CENTIMETERS = 3;
+ }
+
+ /**
+ * Constants for {@link TAG_PHOTOMETRIC_INTERPRETATION}
+ */
+ public static interface PhotometricInterpretation {
+ public static final short RGB = 2;
+ public static final short YCBCR = 6;
+ }
+
+ /**
+ * Constants for {@link TAG_PLANAR_CONFIGURATION}
+ */
+ public static interface PlanarConfiguration {
+ public static final short CHUNKY = 1;
+ public static final short PLANAR = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_EXPOSURE_PROGRAM}
+ */
+ public static interface ExposureProgram {
+ public static final short NOT_DEFINED = 0;
+ public static final short MANUAL = 1;
+ public static final short NORMAL_PROGRAM = 2;
+ public static final short APERTURE_PRIORITY = 3;
+ public static final short SHUTTER_PRIORITY = 4;
+ public static final short CREATIVE_PROGRAM = 5;
+ public static final short ACTION_PROGRAM = 6;
+ public static final short PROTRAIT_MODE = 7;
+ public static final short LANDSCAPE_MODE = 8;
+ }
+
+ /**
+ * Constants for {@link TAG_METERING_MODE}
+ */
+ public static interface MeteringMode {
+ public static final short UNKNOWN = 0;
+ public static final short AVERAGE = 1;
+ public static final short CENTER_WEIGHTED_AVERAGE = 2;
+ public static final short SPOT = 3;
+ public static final short MULTISPOT = 4;
+ public static final short PATTERN = 5;
+ public static final short PARTAIL = 6;
+ public static final short OTHER = 255;
+ }
+
+ /**
+ * Constants for {@link TAG_FLASH} As the definition in Jeita EXIF 2.2
+ * standard, we can treat this constant as bitwise flag.
+ * <p>
+ * e.g.
+ * <p>
+ * short flash = FIRED | RETURN_STROBE_RETURN_LIGHT_DETECTED |
+ * MODE_AUTO_MODE
+ */
+ public static interface Flash {
+ // LSB
+ public static final short DID_NOT_FIRED = 0;
+ public static final short FIRED = 1;
+ // 1st~2nd bits
+ public static final short RETURN_NO_STROBE_RETURN_DETECTION_FUNCTION = 0 << 1;
+ public static final short RETURN_STROBE_RETURN_LIGHT_NOT_DETECTED = 2 << 1;
+ public static final short RETURN_STROBE_RETURN_LIGHT_DETECTED = 3 << 1;
+ // 3rd~4th bits
+ public static final short MODE_UNKNOWN = 0 << 3;
+ public static final short MODE_COMPULSORY_FLASH_FIRING = 1 << 3;
+ public static final short MODE_COMPULSORY_FLASH_SUPPRESSION = 2 << 3;
+ public static final short MODE_AUTO_MODE = 3 << 3;
+ // 5th bit
+ public static final short FUNCTION_PRESENT = 0 << 5;
+ public static final short FUNCTION_NO_FUNCTION = 1 << 5;
+ // 6th bit
+ public static final short RED_EYE_REDUCTION_NO_OR_UNKNOWN = 0 << 6;
+ public static final short RED_EYE_REDUCTION_SUPPORT = 1 << 6;
+ }
+
+ /**
+ * Constants for {@link TAG_COLOR_SPACE}
+ */
+ public static interface ColorSpace {
+ public static final short SRGB = 1;
+ public static final short UNCALIBRATED = (short) 0xFFFF;
+ }
+
+ /**
+ * Constants for {@link TAG_EXPOSURE_MODE}
+ */
+ public static interface ExposureMode {
+ public static final short AUTO_EXPOSURE = 0;
+ public static final short MANUAL_EXPOSURE = 1;
+ public static final short AUTO_BRACKET = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_WHITE_BALANCE}
+ */
+ public static interface WhiteBalance {
+ public static final short AUTO = 0;
+ public static final short MANUAL = 1;
+ }
+
+ /**
+ * Constants for {@link TAG_SCENE_CAPTURE_TYPE}
+ */
+ public static interface SceneCapture {
+ public static final short STANDARD = 0;
+ public static final short LANDSCAPE = 1;
+ public static final short PROTRAIT = 2;
+ public static final short NIGHT_SCENE = 3;
+ }
+
+ /**
+ * Constants for {@link TAG_COMPONENTS_CONFIGURATION}
+ */
+ public static interface ComponentsConfiguration {
+ public static final short NOT_EXIST = 0;
+ public static final short Y = 1;
+ public static final short CB = 2;
+ public static final short CR = 3;
+ public static final short R = 4;
+ public static final short G = 5;
+ public static final short B = 6;
+ }
+
+ /**
+ * Constants for {@link TAG_LIGHT_SOURCE}
+ */
+ public static interface LightSource {
+ public static final short UNKNOWN = 0;
+ public static final short DAYLIGHT = 1;
+ public static final short FLUORESCENT = 2;
+ public static final short TUNGSTEN = 3;
+ public static final short FLASH = 4;
+ public static final short FINE_WEATHER = 9;
+ public static final short CLOUDY_WEATHER = 10;
+ public static final short SHADE = 11;
+ public static final short DAYLIGHT_FLUORESCENT = 12;
+ public static final short DAY_WHITE_FLUORESCENT = 13;
+ public static final short COOL_WHITE_FLUORESCENT = 14;
+ public static final short WHITE_FLUORESCENT = 15;
+ public static final short STANDARD_LIGHT_A = 17;
+ public static final short STANDARD_LIGHT_B = 18;
+ public static final short STANDARD_LIGHT_C = 19;
+ public static final short D55 = 20;
+ public static final short D65 = 21;
+ public static final short D75 = 22;
+ public static final short D50 = 23;
+ public static final short ISO_STUDIO_TUNGSTEN = 24;
+ public static final short OTHER = 255;
+ }
+
+ /**
+ * Constants for {@link TAG_SENSING_METHOD}
+ */
+ public static interface SensingMethod {
+ public static final short NOT_DEFINED = 1;
+ public static final short ONE_CHIP_COLOR = 2;
+ public static final short TWO_CHIP_COLOR = 3;
+ public static final short THREE_CHIP_COLOR = 4;
+ public static final short COLOR_SEQUENTIAL_AREA = 5;
+ public static final short TRILINEAR = 7;
+ public static final short COLOR_SEQUENTIAL_LINEAR = 8;
+ }
+
+ /**
+ * Constants for {@link TAG_FILE_SOURCE}
+ */
+ public static interface FileSource {
+ public static final short DSC = 3;
+ }
+
+ /**
+ * Constants for {@link TAG_SCENE_TYPE}
+ */
+ public static interface SceneType {
+ public static final short DIRECT_PHOTOGRAPHED = 1;
+ }
+
+ /**
+ * Constants for {@link TAG_GAIN_CONTROL}
+ */
+ public static interface GainControl {
+ public static final short NONE = 0;
+ public static final short LOW_UP = 1;
+ public static final short HIGH_UP = 2;
+ public static final short LOW_DOWN = 3;
+ public static final short HIGH_DOWN = 4;
+ }
+
+ /**
+ * Constants for {@link TAG_CONTRAST}
+ */
+ public static interface Contrast {
+ public static final short NORMAL = 0;
+ public static final short SOFT = 1;
+ public static final short HARD = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_SATURATION}
+ */
+ public static interface Saturation {
+ public static final short NORMAL = 0;
+ public static final short LOW = 1;
+ public static final short HIGH = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_SHARPNESS}
+ */
+ public static interface Sharpness {
+ public static final short NORMAL = 0;
+ public static final short SOFT = 1;
+ public static final short HARD = 2;
+ }
+
+ /**
+ * Constants for {@link TAG_SUBJECT_DISTANCE}
+ */
+ public static interface SubjectDistance {
+ public static final short UNKNOWN = 0;
+ public static final short MACRO = 1;
+ public static final short CLOSE_VIEW = 2;
+ public static final short DISTANT_VIEW = 3;
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_LATITUDE_REF},
+ * {@link TAG_GPS_DEST_LATITUDE_REF}
+ */
+ public static interface GpsLatitudeRef {
+ public static final String NORTH = "N";
+ public static final String SOUTH = "S";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_LONGITUDE_REF},
+ * {@link TAG_GPS_DEST_LONGITUDE_REF}
+ */
+ public static interface GpsLongitudeRef {
+ public static final String EAST = "E";
+ public static final String WEST = "W";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_ALTITUDE_REF}
+ */
+ public static interface GpsAltitudeRef {
+ public static final short SEA_LEVEL = 0;
+ public static final short SEA_LEVEL_NEGATIVE = 1;
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_STATUS}
+ */
+ public static interface GpsStatus {
+ public static final String IN_PROGRESS = "A";
+ public static final String INTEROPERABILITY = "V";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_MEASURE_MODE}
+ */
+ public static interface GpsMeasureMode {
+ public static final String MODE_2_DIMENSIONAL = "2";
+ public static final String MODE_3_DIMENSIONAL = "3";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_SPEED_REF},
+ * {@link TAG_GPS_DEST_DISTANCE_REF}
+ */
+ public static interface GpsSpeedRef {
+ public static final String KILOMETERS = "K";
+ public static final String MILES = "M";
+ public static final String KNOTS = "N";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_TRACK_REF},
+ * {@link TAG_GPS_IMG_DIRECTION_REF}, {@link TAG_GPS_DEST_BEARING_REF}
+ */
+ public static interface GpsTrackRef {
+ public static final String TRUE_DIRECTION = "T";
+ public static final String MAGNETIC_DIRECTION = "M";
+ }
+
+ /**
+ * Constants for {@link TAG_GPS_DIFFERENTIAL}
+ */
+ public static interface GpsDifferential {
+ public static final short WITHOUT_DIFFERENTIAL_CORRECTION = 0;
+ public static final short DIFFERENTIAL_CORRECTION_APPLIED = 1;
+ }
+
+ private static final String NULL_ARGUMENT_STRING = "Argument is null";
+ private ExifData mData = new ExifData(DEFAULT_BYTE_ORDER);
+ public static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
+
+ public ExifInterface() {
+ mGPSDateStampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+
+ /**
+ * Reads the exif tags from a byte array, clearing this ExifInterface
+ * object's existing exif tags.
+ *
+ * @param jpeg a byte array containing a jpeg compressed image.
+ * @throws IOException
+ */
+ public void readExif(byte[] jpeg) throws IOException {
+ readExif(new ByteArrayInputStream(jpeg));
+ }
+
+ /**
+ * Reads the exif tags from an InputStream, clearing this ExifInterface
+ * object's existing exif tags.
+ *
+ * @param inStream an InputStream containing a jpeg compressed image.
+ * @throws IOException
+ */
+ public void readExif(InputStream inStream) throws IOException {
+ if (inStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ ExifData d = null;
+ try {
+ d = new ExifReader(this).read(inStream);
+ } catch (ExifInvalidFormatException e) {
+ throw new IOException("Invalid exif format : " + e);
+ }
+ mData = d;
+ }
+
+ /**
+ * Reads the exif tags from a file, clearing this ExifInterface object's
+ * existing exif tags.
+ *
+ * @param inFileName a string representing the filepath to jpeg file.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void readExif(String inFileName) throws FileNotFoundException, IOException {
+ if (inFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ InputStream is = null;
+ try {
+ is = (InputStream) new BufferedInputStream(new FileInputStream(inFileName));
+ readExif(is);
+ } catch (IOException e) {
+ closeSilently(is);
+ throw e;
+ }
+ is.close();
+ }
+
+ /**
+ * Sets the exif tags, clearing this ExifInterface object's existing exif
+ * tags.
+ *
+ * @param tags a collection of exif tags to set.
+ */
+ public void setExif(Collection<ExifTag> tags) {
+ clearExif();
+ setTags(tags);
+ }
+
+ /**
+ * Clears this ExifInterface object's existing exif tags.
+ */
+ public void clearExif() {
+ mData = new ExifData(DEFAULT_BYTE_ORDER);
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg image,
+ * removing prior exif tags.
+ *
+ * @param jpeg a byte array containing a jpeg compressed image.
+ * @param exifOutStream an OutputStream to which the jpeg image with added
+ * exif tags will be written.
+ * @throws IOException
+ */
+ public void writeExif(byte[] jpeg, OutputStream exifOutStream) throws IOException {
+ if (jpeg == null || exifOutStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = getExifWriterStream(exifOutStream);
+ s.write(jpeg, 0, jpeg.length);
+ s.flush();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg compressed
+ * bitmap, removing prior exif tags.
+ *
+ * @param bmap a bitmap to compress and write exif into.
+ * @param exifOutStream the OutputStream to which the jpeg image with added
+ * exif tags will be written.
+ * @throws IOException
+ */
+ public void writeExif(Bitmap bmap, OutputStream exifOutStream) throws IOException {
+ if (bmap == null || exifOutStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = getExifWriterStream(exifOutStream);
+ bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
+ s.flush();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg stream,
+ * removing prior exif tags.
+ *
+ * @param jpegStream an InputStream containing a jpeg compressed image.
+ * @param exifOutStream an OutputStream to which the jpeg image with added
+ * exif tags will be written.
+ * @throws IOException
+ */
+ public void writeExif(InputStream jpegStream, OutputStream exifOutStream) throws IOException {
+ if (jpegStream == null || exifOutStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = getExifWriterStream(exifOutStream);
+ doExifStreamIO(jpegStream, s);
+ s.flush();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg image,
+ * removing prior exif tags.
+ *
+ * @param jpeg a byte array containing a jpeg compressed image.
+ * @param exifOutFileName a String containing the filepath to which the jpeg
+ * image with added exif tags will be written.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void writeExif(byte[] jpeg, String exifOutFileName) throws FileNotFoundException,
+ IOException {
+ if (jpeg == null || exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = null;
+ try {
+ s = getExifWriterStream(exifOutFileName);
+ s.write(jpeg, 0, jpeg.length);
+ s.flush();
+ } catch (IOException e) {
+ closeSilently(s);
+ throw e;
+ }
+ s.close();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg compressed
+ * bitmap, removing prior exif tags.
+ *
+ * @param bmap a bitmap to compress and write exif into.
+ * @param exifOutFileName a String containing the filepath to which the jpeg
+ * image with added exif tags will be written.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void writeExif(Bitmap bmap, String exifOutFileName) throws FileNotFoundException,
+ IOException {
+ if (bmap == null || exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = null;
+ try {
+ s = getExifWriterStream(exifOutFileName);
+ bmap.compress(Bitmap.CompressFormat.JPEG, 90, s);
+ s.flush();
+ } catch (IOException e) {
+ closeSilently(s);
+ throw e;
+ }
+ s.close();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg stream,
+ * removing prior exif tags.
+ *
+ * @param jpegStream an InputStream containing a jpeg compressed image.
+ * @param exifOutFileName a String containing the filepath to which the jpeg
+ * image with added exif tags will be written.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void writeExif(InputStream jpegStream, String exifOutFileName)
+ throws FileNotFoundException, IOException {
+ if (jpegStream == null || exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream s = null;
+ try {
+ s = getExifWriterStream(exifOutFileName);
+ doExifStreamIO(jpegStream, s);
+ s.flush();
+ } catch (IOException e) {
+ closeSilently(s);
+ throw e;
+ }
+ s.close();
+ }
+
+ /**
+ * Writes the tags from this ExifInterface object into a jpeg file, removing
+ * prior exif tags.
+ *
+ * @param jpegFileName a String containing the filepath for a jpeg file.
+ * @param exifOutFileName a String containing the filepath to which the jpeg
+ * image with added exif tags will be written.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public void writeExif(String jpegFileName, String exifOutFileName)
+ throws FileNotFoundException, IOException {
+ if (jpegFileName == null || exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ InputStream is = null;
+ try {
+ is = new FileInputStream(jpegFileName);
+ writeExif(is, exifOutFileName);
+ } catch (IOException e) {
+ closeSilently(is);
+ throw e;
+ }
+ is.close();
+ }
+
+ /**
+ * Wraps an OutputStream object with an ExifOutputStream. Exif tags in this
+ * ExifInterface object will be added to a jpeg image written to this
+ * stream, removing prior exif tags. Other methods of this ExifInterface
+ * object should not be called until the returned OutputStream has been
+ * closed.
+ *
+ * @param outStream an OutputStream to wrap.
+ * @return an OutputStream that wraps the outStream parameter, and adds exif
+ * metadata. A jpeg image should be written to this stream.
+ */
+ public OutputStream getExifWriterStream(OutputStream outStream) {
+ if (outStream == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ ExifOutputStream eos = new ExifOutputStream(outStream, this);
+ eos.setExifData(mData);
+ return eos;
+ }
+
+ /**
+ * Returns an OutputStream object that writes to a file. Exif tags in this
+ * ExifInterface object will be added to a jpeg image written to this
+ * stream, removing prior exif tags. Other methods of this ExifInterface
+ * object should not be called until the returned OutputStream has been
+ * closed.
+ *
+ * @param exifOutFileName an String containing a filepath for a jpeg file.
+ * @return an OutputStream that writes to the exifOutFileName file, and adds
+ * exif metadata. A jpeg image should be written to this stream.
+ * @throws FileNotFoundException
+ */
+ public OutputStream getExifWriterStream(String exifOutFileName) throws FileNotFoundException {
+ if (exifOutFileName == null) {
+ throw new IllegalArgumentException(NULL_ARGUMENT_STRING);
+ }
+ OutputStream out = null;
+ try {
+ out = (OutputStream) new FileOutputStream(exifOutFileName);
+ } catch (FileNotFoundException e) {
+ closeSilently(out);
+ throw e;
+ }
+ return getExifWriterStream(out);
+ }
+
+ /**
+ * Attempts to do an in-place rewrite the exif metadata in a file for the
+ * given tags. If tags do not exist or do not have the same size as the
+ * existing exif tags, this method will fail.
+ *
+ * @param filename a String containing a filepath for a jpeg file with exif
+ * tags to rewrite.
+ * @param tags tags that will be written into the jpeg file over existing
+ * tags if possible.
+ * @return true if success, false if could not overwrite. If false, no
+ * changes are made to the file.
+ * @throws FileNotFoundException
+ * @throws IOException
+ */
+ public boolean rewriteExif(String filename, Collection<ExifTag> tags)
+ throws FileNotFoundException, IOException {
+ RandomAccessFile file = null;
+ InputStream is = null;
+ boolean ret;
+ try {
+ File temp = new File(filename);
+ is = new BufferedInputStream(new FileInputStream(temp));
+
+ // Parse beginning of APP1 in exif to find size of exif header.
+ ExifParser parser = null;
+ try {
+ parser = ExifParser.parse(is, this);
+ } catch (ExifInvalidFormatException e) {
+ throw new IOException("Invalid exif format : ", e);
+ }
+ long exifSize = parser.getOffsetToExifEndFromSOF();
+
+ // Free up resources
+ is.close();
+ is = null;
+
+ // Open file for memory mapping.
+ file = new RandomAccessFile(temp, "rw");
+ long fileLength = file.length();
+ if (fileLength < exifSize) {
+ throw new IOException("Filesize changed during operation");
+ }
+
+ // Map only exif header into memory.
+ ByteBuffer buf = file.getChannel().map(MapMode.READ_WRITE, 0, exifSize);
+
+ // Attempt to overwrite tag values without changing lengths (avoids
+ // file copy).
+ ret = rewriteExif(buf, tags);
+ } catch (IOException e) {
+ closeSilently(file);
+ throw e;
+ } finally {
+ closeSilently(is);
+ }
+ file.close();
+ return ret;
+ }
+
+ /**
+ * Attempts to do an in-place rewrite the exif metadata in a ByteBuffer for
+ * the given tags. If tags do not exist or do not have the same size as the
+ * existing exif tags, this method will fail.
+ *
+ * @param buf a ByteBuffer containing a jpeg file with existing exif tags to
+ * rewrite.
+ * @param tags tags that will be written into the jpeg ByteBuffer over
+ * existing tags if possible.
+ * @return true if success, false if could not overwrite. If false, no
+ * changes are made to the ByteBuffer.
+ * @throws IOException
+ */
+ public boolean rewriteExif(ByteBuffer buf, Collection<ExifTag> tags) throws IOException {
+ ExifModifier mod = null;
+ try {
+ mod = new ExifModifier(buf, this);
+ for (ExifTag t : tags) {
+ mod.modifyTag(t);
+ }
+ return mod.commit();
+ } catch (ExifInvalidFormatException e) {
+ throw new IOException("Invalid exif format : " + e);
+ }
+ }
+
+ /**
+ * Attempts to do an in-place rewrite of the exif metadata. If this fails,
+ * fall back to overwriting file. This preserves tags that are not being
+ * rewritten.
+ *
+ * @param filename a String containing a filepath for a jpeg file.
+ * @param tags tags that will be written into the jpeg file over existing
+ * tags if possible.
+ * @throws FileNotFoundException
+ * @throws IOException
+ * @see #rewriteExif
+ */
+ public void forceRewriteExif(String filename, Collection<ExifTag> tags)
+ throws FileNotFoundException,
+ IOException {
+ // Attempt in-place write
+ if (!rewriteExif(filename, tags)) {
+ // Fall back to doing a copy
+ ExifData tempData = mData;
+ mData = new ExifData(DEFAULT_BYTE_ORDER);
+ FileInputStream is = null;
+ ByteArrayOutputStream bytes = null;
+ try {
+ is = new FileInputStream(filename);
+ bytes = new ByteArrayOutputStream();
+ doExifStreamIO(is, bytes);
+ byte[] imageBytes = bytes.toByteArray();
+ readExif(imageBytes);
+ setTags(tags);
+ writeExif(imageBytes, filename);
+ } catch (IOException e) {
+ closeSilently(is);
+ throw e;
+ } finally {
+ is.close();
+ // Prevent clobbering of mData
+ mData = tempData;
+ }
+ }
+ }
+
+ /**
+ * Attempts to do an in-place rewrite of the exif metadata using the tags in
+ * this ExifInterface object. If this fails, fall back to overwriting file.
+ * This preserves tags that are not being rewritten.
+ *
+ * @param filename a String containing a filepath for a jpeg file.
+ * @throws FileNotFoundException
+ * @throws IOException
+ * @see #rewriteExif
+ */
+ public void forceRewriteExif(String filename) throws FileNotFoundException, IOException {
+ forceRewriteExif(filename, getAllTags());
+ }
+
+ /**
+ * Get the exif tags in this ExifInterface object or null if none exist.
+ *
+ * @return a List of {@link ExifTag}s.
+ */
+ public List<ExifTag> getAllTags() {
+ return mData.getAllTags();
+ }
+
+ /**
+ * Returns a list of ExifTags that share a TID (which can be obtained by
+ * calling {@link #getTrueTagKey} on a defined tag constant) or null if none
+ * exist.
+ *
+ * @param tagId a TID as defined in the exif standard (or with
+ * {@link #defineTag}).
+ * @return a List of {@link ExifTag}s.
+ */
+ public List<ExifTag> getTagsForTagId(short tagId) {
+ return mData.getAllTagsForTagId(tagId);
+ }
+
+ /**
+ * Returns a list of ExifTags that share an IFD (which can be obtained by
+ * calling {@link #getTrueIFD} on a defined tag constant) or null if none
+ * exist.
+ *
+ * @param ifdId an IFD as defined in the exif standard (or with
+ * {@link #defineTag}).
+ * @return a List of {@link ExifTag}s.
+ */
+ public List<ExifTag> getTagsForIfdId(int ifdId) {
+ return mData.getAllTagsForIfd(ifdId);
+ }
+
+ /**
+ * Gets an ExifTag for an IFD other than the tag's default.
+ *
+ * @see #getTag
+ */
+ public ExifTag getTag(int tagId, int ifdId) {
+ if (!ExifTag.isValidIfd(ifdId)) {
+ return null;
+ }
+ return mData.getTag(getTrueTagKey(tagId), ifdId);
+ }
+
+ /**
+ * Returns the ExifTag in that tag's default IFD for a defined tag constant
+ * or null if none exists.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return an {@link ExifTag} or null if none exists.
+ */
+ public ExifTag getTag(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTag(tagId, ifdId);
+ }
+
+ /**
+ * Gets a tag value for an IFD other than the tag's default.
+ *
+ * @see #getTagValue
+ */
+ public Object getTagValue(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ return (t == null) ? null : t.getValue();
+ }
+
+ /**
+ * Returns the value of the ExifTag in that tag's default IFD for a defined
+ * tag constant or null if none exists or the value could not be cast into
+ * the return type.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return the value of the ExifTag or null if none exists.
+ */
+ public Object getTagValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagValue(tagId, ifdId);
+ }
+
+ /*
+ * Getter methods that are similar to getTagValue. Null is returned if the
+ * tag value cannot be cast into the return type.
+ */
+
+ /**
+ * @see #getTagValue
+ */
+ public String getTagStringValue(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsString();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public String getTagStringValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagStringValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Long getTagLongValue(int tagId, int ifdId) {
+ long[] l = getTagLongValues(tagId, ifdId);
+ if (l == null || l.length <= 0) {
+ return null;
+ }
+ return new Long(l[0]);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Long getTagLongValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagLongValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Integer getTagIntValue(int tagId, int ifdId) {
+ int[] l = getTagIntValues(tagId, ifdId);
+ if (l == null || l.length <= 0) {
+ return null;
+ }
+ return new Integer(l[0]);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Integer getTagIntValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagIntValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Byte getTagByteValue(int tagId, int ifdId) {
+ byte[] l = getTagByteValues(tagId, ifdId);
+ if (l == null || l.length <= 0) {
+ return null;
+ }
+ return new Byte(l[0]);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Byte getTagByteValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagByteValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Rational getTagRationalValue(int tagId, int ifdId) {
+ Rational[] l = getTagRationalValues(tagId, ifdId);
+ if (l == null || l.length == 0) {
+ return null;
+ }
+ return new Rational(l[0]);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Rational getTagRationalValue(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagRationalValue(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public long[] getTagLongValues(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsLongs();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public long[] getTagLongValues(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagLongValues(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public int[] getTagIntValues(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsInts();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public int[] getTagIntValues(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagIntValues(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public byte[] getTagByteValues(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsBytes();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public byte[] getTagByteValues(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagByteValues(tagId, ifdId);
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Rational[] getTagRationalValues(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return null;
+ }
+ return t.getValueAsRationals();
+ }
+
+ /**
+ * @see #getTagValue
+ */
+ public Rational[] getTagRationalValues(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return getTagRationalValues(tagId, ifdId);
+ }
+
+ /**
+ * Checks whether a tag has a defined number of elements.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return true if the tag has a defined number of elements.
+ */
+ public boolean isTagCountDefined(int tagId) {
+ int info = getTagInfo().get(tagId);
+ // No value in info can be zero, as all tags have a non-zero type
+ if (info == 0) {
+ return false;
+ }
+ return getComponentCountFromInfo(info) != ExifTag.SIZE_UNDEFINED;
+ }
+
+ /**
+ * Gets the defined number of elements for a tag.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return the number of elements or {@link ExifTag#SIZE_UNDEFINED} if the
+ * tag or the number of elements is not defined.
+ */
+ public int getDefinedTagCount(int tagId) {
+ int info = getTagInfo().get(tagId);
+ if (info == 0) {
+ return ExifTag.SIZE_UNDEFINED;
+ }
+ return getComponentCountFromInfo(info);
+ }
+
+ /**
+ * Gets the number of elements for an ExifTag in a given IFD.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param ifdId the IFD containing the ExifTag to check.
+ * @return the number of elements in the ExifTag, if the tag's size is
+ * undefined this will return the actual number of elements that is
+ * in the ExifTag's value.
+ */
+ public int getActualTagCount(int tagId, int ifdId) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return 0;
+ }
+ return t.getComponentCount();
+ }
+
+ /**
+ * Gets the default IFD for a tag.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return the default IFD for a tag definition or {@link #IFD_NULL} if no
+ * definition exists.
+ */
+ public int getDefinedTagDefaultIfd(int tagId) {
+ int info = getTagInfo().get(tagId);
+ if (info == DEFINITION_NULL) {
+ return IFD_NULL;
+ }
+ return getTrueIfd(tagId);
+ }
+
+ /**
+ * Gets the defined type for a tag.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @return the type.
+ * @see ExifTag#getDataType()
+ */
+ public short getDefinedTagType(int tagId) {
+ int info = getTagInfo().get(tagId);
+ if (info == 0) {
+ return -1;
+ }
+ return getTypeFromInfo(info);
+ }
+
+ /**
+ * Returns true if tag TID is one of the following: {@link TAG_EXIF_IFD},
+ * {@link TAG_GPS_IFD}, {@link TAG_JPEG_INTERCHANGE_FORMAT},
+ * {@link TAG_STRIP_OFFSETS}, {@link TAG_INTEROPERABILITY_IFD}
+ * <p>
+ * Note: defining tags with these TID's is disallowed.
+ *
+ * @param tag a tag's TID (can be obtained from a defined tag constant with
+ * {@link #getTrueTagKey}).
+ * @return true if the TID is that of an offset tag.
+ */
+ protected static boolean isOffsetTag(short tag) {
+ return sOffsetTags.contains(tag);
+ }
+
+ /**
+ * Creates a tag for a defined tag constant in a given IFD if that IFD is
+ * allowed for the tag. This method will fail anytime the appropriate
+ * {@link ExifTag#setValue} for this tag's datatype would fail.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param ifdId the IFD that the tag should be in.
+ * @param val the value of the tag to set.
+ * @return an ExifTag object or null if one could not be constructed.
+ * @see #buildTag
+ */
+ public ExifTag buildTag(int tagId, int ifdId, Object val) {
+ int info = getTagInfo().get(tagId);
+ if (info == 0 || val == null) {
+ return null;
+ }
+ short type = getTypeFromInfo(info);
+ int definedCount = getComponentCountFromInfo(info);
+ boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
+ if (!ExifInterface.isIfdAllowed(info, ifdId)) {
+ return null;
+ }
+ ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
+ if (!t.setValue(val)) {
+ return null;
+ }
+ return t;
+ }
+
+ /**
+ * Creates a tag for a defined tag constant in the tag's default IFD.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param val the tag's value.
+ * @return an ExifTag object.
+ */
+ public ExifTag buildTag(int tagId, Object val) {
+ int ifdId = getTrueIfd(tagId);
+ return buildTag(tagId, ifdId, val);
+ }
+
+ protected ExifTag buildUninitializedTag(int tagId) {
+ int info = getTagInfo().get(tagId);
+ if (info == 0) {
+ return null;
+ }
+ short type = getTypeFromInfo(info);
+ int definedCount = getComponentCountFromInfo(info);
+ boolean hasDefinedCount = (definedCount != ExifTag.SIZE_UNDEFINED);
+ int ifdId = getTrueIfd(tagId);
+ ExifTag t = new ExifTag(getTrueTagKey(tagId), type, definedCount, ifdId, hasDefinedCount);
+ return t;
+ }
+
+ /**
+ * Sets the value of an ExifTag if it exists in the given IFD. The value
+ * must be the correct type and length for that ExifTag.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param ifdId the IFD that the ExifTag is in.
+ * @param val the value to set.
+ * @return true if success, false if the ExifTag doesn't exist or the value
+ * is the wrong type/length.
+ * @see #setTagValue
+ */
+ public boolean setTagValue(int tagId, int ifdId, Object val) {
+ ExifTag t = getTag(tagId, ifdId);
+ if (t == null) {
+ return false;
+ }
+ return t.setValue(val);
+ }
+
+ /**
+ * Sets the value of an ExifTag if it exists it's default IFD. The value
+ * must be the correct type and length for that ExifTag.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param val the value to set.
+ * @return true if success, false if the ExifTag doesn't exist or the value
+ * is the wrong type/length.
+ */
+ public boolean setTagValue(int tagId, Object val) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ return setTagValue(tagId, ifdId, val);
+ }
+
+ /**
+ * Puts an ExifTag into this ExifInterface object's tags, removing a
+ * previous ExifTag with the same TID and IFD. The IFD it is put into will
+ * be the one the tag was created with in {@link #buildTag}.
+ *
+ * @param tag an ExifTag to put into this ExifInterface's tags.
+ * @return the previous ExifTag with the same TID and IFD or null if none
+ * exists.
+ */
+ public ExifTag setTag(ExifTag tag) {
+ return mData.addTag(tag);
+ }
+
+ /**
+ * Puts a collection of ExifTags into this ExifInterface objects's tags. Any
+ * previous ExifTags with the same TID and IFDs will be removed.
+ *
+ * @param tags a Collection of ExifTags.
+ * @see #setTag
+ */
+ public void setTags(Collection<ExifTag> tags) {
+ for (ExifTag t : tags) {
+ setTag(t);
+ }
+ }
+
+ /**
+ * Removes the ExifTag for a tag constant from the given IFD.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ * @param ifdId the IFD of the ExifTag to remove.
+ */
+ public void deleteTag(int tagId, int ifdId) {
+ mData.removeTag(getTrueTagKey(tagId), ifdId);
+ }
+
+ /**
+ * Removes the ExifTag for a tag constant from that tag's default IFD.
+ *
+ * @param tagId a tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ */
+ public void deleteTag(int tagId) {
+ int ifdId = getDefinedTagDefaultIfd(tagId);
+ deleteTag(tagId, ifdId);
+ }
+
+ /**
+ * Creates a new tag definition in this ExifInterface object for a given TID
+ * and default IFD. Creating a definition with the same TID and default IFD
+ * as a previous definition will override it.
+ *
+ * @param tagId the TID for the tag.
+ * @param defaultIfd the default IFD for the tag.
+ * @param tagType the type of the tag (see {@link ExifTag#getDataType()}).
+ * @param defaultComponentCount the number of elements of this tag's type in
+ * the tags value.
+ * @param allowedIfds the IFD's this tag is allowed to be put in.
+ * @return the defined tag constant (e.g. {@link #TAG_IMAGE_WIDTH}) or
+ * {@link #TAG_NULL} if the definition could not be made.
+ */
+ public int setTagDefinition(short tagId, int defaultIfd, short tagType,
+ short defaultComponentCount, int[] allowedIfds) {
+ if (sBannedDefines.contains(tagId)) {
+ return TAG_NULL;
+ }
+ if (ExifTag.isValidType(tagType) && ExifTag.isValidIfd(defaultIfd)) {
+ int tagDef = defineTag(defaultIfd, tagId);
+ if (tagDef == TAG_NULL) {
+ return TAG_NULL;
+ }
+ int[] otherDefs = getTagDefinitionsForTagId(tagId);
+ SparseIntArray infos = getTagInfo();
+ // Make sure defaultIfd is in allowedIfds
+ boolean defaultCheck = false;
+ for (int i : allowedIfds) {
+ if (defaultIfd == i) {
+ defaultCheck = true;
+ }
+ if (!ExifTag.isValidIfd(i)) {
+ return TAG_NULL;
+ }
+ }
+ if (!defaultCheck) {
+ return TAG_NULL;
+ }
+
+ int ifdFlags = getFlagsFromAllowedIfds(allowedIfds);
+ // Make sure no identical tags can exist in allowedIfds
+ if (otherDefs != null) {
+ for (int def : otherDefs) {
+ int tagInfo = infos.get(def);
+ int allowedFlags = getAllowedIfdFlagsFromInfo(tagInfo);
+ if ((ifdFlags & allowedFlags) != 0) {
+ return TAG_NULL;
+ }
+ }
+ }
+ getTagInfo().put(tagDef, ifdFlags << 24 | (tagType << 16) | defaultComponentCount);
+ return tagDef;
+ }
+ return TAG_NULL;
+ }
+
+ protected int getTagDefinition(short tagId, int defaultIfd) {
+ return getTagInfo().get(defineTag(defaultIfd, tagId));
+ }
+
+ protected int[] getTagDefinitionsForTagId(short tagId) {
+ int[] ifds = IfdData.getIfds();
+ int[] defs = new int[ifds.length];
+ int counter = 0;
+ SparseIntArray infos = getTagInfo();
+ for (int i : ifds) {
+ int def = defineTag(i, tagId);
+ if (infos.get(def) != DEFINITION_NULL) {
+ defs[counter++] = def;
+ }
+ }
+ if (counter == 0) {
+ return null;
+ }
+
+ return Arrays.copyOfRange(defs, 0, counter);
+ }
+
+ protected int getTagDefinitionForTag(ExifTag tag) {
+ short type = tag.getDataType();
+ int count = tag.getComponentCount();
+ int ifd = tag.getIfd();
+ return getTagDefinitionForTag(tag.getTagId(), type, count, ifd);
+ }
+
+ protected int getTagDefinitionForTag(short tagId, short type, int count, int ifd) {
+ int[] defs = getTagDefinitionsForTagId(tagId);
+ if (defs == null) {
+ return TAG_NULL;
+ }
+ SparseIntArray infos = getTagInfo();
+ int ret = TAG_NULL;
+ for (int i : defs) {
+ int info = infos.get(i);
+ short def_type = getTypeFromInfo(info);
+ int def_count = getComponentCountFromInfo(info);
+ int[] def_ifds = getAllowedIfdsFromInfo(info);
+ boolean valid_ifd = false;
+ for (int j : def_ifds) {
+ if (j == ifd) {
+ valid_ifd = true;
+ break;
+ }
+ }
+ if (valid_ifd && type == def_type
+ && (count == def_count || def_count == ExifTag.SIZE_UNDEFINED)) {
+ ret = i;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Removes a tag definition for given defined tag constant.
+ *
+ * @param tagId a defined tag constant, e.g. {@link #TAG_IMAGE_WIDTH}.
+ */
+ public void removeTagDefinition(int tagId) {
+ getTagInfo().delete(tagId);
+ }
+
+ /**
+ * Resets tag definitions to the default ones.
+ */
+ public void resetTagDefinitions() {
+ mTagInfo = null;
+ }
+
+ /**
+ * Returns the thumbnail from IFD1 as a bitmap, or null if none exists.
+ *
+ * @return the thumbnail as a bitmap.
+ */
+ public Bitmap getThumbnailBitmap() {
+ if (mData.hasCompressedThumbnail()) {
+ byte[] thumb = mData.getCompressedThumbnail();
+ return BitmapFactory.decodeByteArray(thumb, 0, thumb.length);
+ } else if (mData.hasUncompressedStrip()) {
+ // TODO: implement uncompressed
+ }
+ return null;
+ }
+
+ /**
+ * Returns the thumbnail from IFD1 as a byte array, or null if none exists.
+ * The bytes may either be an uncompressed strip as specified in the exif
+ * standard or a jpeg compressed image.
+ *
+ * @return the thumbnail as a byte array.
+ */
+ public byte[] getThumbnailBytes() {
+ if (mData.hasCompressedThumbnail()) {
+ return mData.getCompressedThumbnail();
+ } else if (mData.hasUncompressedStrip()) {
+ // TODO: implement this
+ }
+ return null;
+ }
+
+ /**
+ * Returns the thumbnail if it is jpeg compressed, or null if none exists.
+ *
+ * @return the thumbnail as a byte array.
+ */
+ public byte[] getThumbnail() {
+ return mData.getCompressedThumbnail();
+ }
+
+ /**
+ * Check if thumbnail is compressed.
+ *
+ * @return true if the thumbnail is compressed.
+ */
+ public boolean isThumbnailCompressed() {
+ return mData.hasCompressedThumbnail();
+ }
+
+ /**
+ * Check if thumbnail exists.
+ *
+ * @return true if a compressed thumbnail exists.
+ */
+ public boolean hasThumbnail() {
+ // TODO: add back in uncompressed strip
+ return mData.hasCompressedThumbnail();
+ }
+
+ // TODO: uncompressed thumbnail setters
+
+ /**
+ * Sets the thumbnail to be a jpeg compressed image. Clears any prior
+ * thumbnail.
+ *
+ * @param thumb a byte array containing a jpeg compressed image.
+ * @return true if the thumbnail was set.
+ */
+ public boolean setCompressedThumbnail(byte[] thumb) {
+ mData.clearThumbnailAndStrips();
+ mData.setCompressedThumbnail(thumb);
+ return true;
+ }
+
+ /**
+ * Sets the thumbnail to be a jpeg compressed bitmap. Clears any prior
+ * thumbnail.
+ *
+ * @param thumb a bitmap to compress to a jpeg thumbnail.
+ * @return true if the thumbnail was set.
+ */
+ public boolean setCompressedThumbnail(Bitmap thumb) {
+ ByteArrayOutputStream thumbnail = new ByteArrayOutputStream();
+ if (!thumb.compress(Bitmap.CompressFormat.JPEG, 90, thumbnail)) {
+ return false;
+ }
+ return setCompressedThumbnail(thumbnail.toByteArray());
+ }
+
+ /**
+ * Clears the compressed thumbnail if it exists.
+ */
+ public void removeCompressedThumbnail() {
+ mData.setCompressedThumbnail(null);
+ }
+
+ // Convenience methods:
+
+ /**
+ * Decodes the user comment tag into string as specified in the EXIF
+ * standard. Returns null if decoding failed.
+ */
+ public String getUserComment() {
+ return mData.getUserComment();
+ }
+
+ /**
+ * Returns the Orientation ExifTag value for a given number of degrees.
+ *
+ * @param degrees the amount an image is rotated in degrees.
+ */
+ public static short getOrientationValueForRotation(int degrees) {
+ degrees %= 360;
+ if (degrees < 0) {
+ degrees += 360;
+ }
+ if (degrees < 90) {
+ return Orientation.TOP_LEFT; // 0 degrees
+ } else if (degrees < 180) {
+ return Orientation.RIGHT_TOP; // 90 degrees cw
+ } else if (degrees < 270) {
+ return Orientation.BOTTOM_LEFT; // 180 degrees
+ } else {
+ return Orientation.RIGHT_BOTTOM; // 270 degrees cw
+ }
+ }
+
+ /**
+ * Returns the rotation degrees corresponding to an ExifTag Orientation
+ * value.
+ *
+ * @param orientation the ExifTag Orientation value.
+ */
+ public static int getRotationForOrientationValue(short orientation) {
+ switch (orientation) {
+ case Orientation.TOP_LEFT:
+ return 0;
+ case Orientation.RIGHT_TOP:
+ return 90;
+ case Orientation.BOTTOM_LEFT:
+ return 180;
+ case Orientation.RIGHT_BOTTOM:
+ return 270;
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * Gets the double representation of the GPS latitude or longitude
+ * coordinate.
+ *
+ * @param coordinate an array of 3 Rationals representing the degrees,
+ * minutes, and seconds of the GPS location as defined in the
+ * exif specification.
+ * @param reference a GPS reference reperesented by a String containing "N",
+ * "S", "E", or "W".
+ * @return the GPS coordinate represented as degrees + minutes/60 +
+ * seconds/3600
+ */
+ public static double convertLatOrLongToDouble(Rational[] coordinate, String reference) {
+ try {
+ double degrees = coordinate[0].toDouble();
+ double minutes = coordinate[1].toDouble();
+ double seconds = coordinate[2].toDouble();
+ double result = degrees + minutes / 60.0 + seconds / 3600.0;
+ if ((reference.equals("S") || reference.equals("W"))) {
+ return -result;
+ }
+ return result;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Gets the GPS latitude and longitude as a pair of doubles from this
+ * ExifInterface object's tags, or null if the necessary tags do not exist.
+ *
+ * @return an array of 2 doubles containing the latitude, and longitude
+ * respectively.
+ * @see #convertLatOrLongToDouble
+ */
+ public double[] getLatLongAsDoubles() {
+ Rational[] latitude = getTagRationalValues(TAG_GPS_LATITUDE);
+ String latitudeRef = getTagStringValue(TAG_GPS_LATITUDE_REF);
+ Rational[] longitude = getTagRationalValues(TAG_GPS_LONGITUDE);
+ String longitudeRef = getTagStringValue(TAG_GPS_LONGITUDE_REF);
+ if (latitude == null || longitude == null || latitudeRef == null || longitudeRef == null
+ || latitude.length < 3 || longitude.length < 3) {
+ return null;
+ }
+ double[] latLon = new double[2];
+ latLon[0] = convertLatOrLongToDouble(latitude, latitudeRef);
+ latLon[1] = convertLatOrLongToDouble(longitude, longitudeRef);
+ return latLon;
+ }
+
+ private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
+ private static final String DATETIME_FORMAT_STR = "yyyy:MM:dd kk:mm:ss";
+ private final DateFormat mDateTimeStampFormat = new SimpleDateFormat(DATETIME_FORMAT_STR);
+ private final DateFormat mGPSDateStampFormat = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
+ private final Calendar mGPSTimeStampCalendar = Calendar
+ .getInstance(TimeZone.getTimeZone("UTC"));
+
+ /**
+ * Creates, formats, and sets the DateTimeStamp tag for one of:
+ * {@link #TAG_DATE_TIME}, {@link #TAG_DATE_TIME_DIGITIZED},
+ * {@link #TAG_DATE_TIME_ORIGINAL}.
+ *
+ * @param tagId one of the DateTimeStamp tags.
+ * @param timestamp a timestamp to format.
+ * @param timezone a TimeZone object.
+ * @return true if success, false if the tag could not be set.
+ */
+ public boolean addDateTimeStampTag(int tagId, long timestamp, TimeZone timezone) {
+ if (tagId == TAG_DATE_TIME || tagId == TAG_DATE_TIME_DIGITIZED
+ || tagId == TAG_DATE_TIME_ORIGINAL) {
+ mDateTimeStampFormat.setTimeZone(timezone);
+ ExifTag t = buildTag(tagId, mDateTimeStampFormat.format(timestamp));
+ if (t == null) {
+ return false;
+ }
+ setTag(t);
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates and sets all to the GPS tags for a give latitude and longitude.
+ *
+ * @param latitude a GPS latitude coordinate.
+ * @param longitude a GPS longitude coordinate.
+ * @return true if success, false if they could not be created or set.
+ */
+ public boolean addGpsTags(double latitude, double longitude) {
+ ExifTag latTag = buildTag(TAG_GPS_LATITUDE, toExifLatLong(latitude));
+ ExifTag longTag = buildTag(TAG_GPS_LONGITUDE, toExifLatLong(longitude));
+ ExifTag latRefTag = buildTag(TAG_GPS_LATITUDE_REF,
+ latitude >= 0 ? ExifInterface.GpsLatitudeRef.NORTH
+ : ExifInterface.GpsLatitudeRef.SOUTH);
+ ExifTag longRefTag = buildTag(TAG_GPS_LONGITUDE_REF,
+ longitude >= 0 ? ExifInterface.GpsLongitudeRef.EAST
+ : ExifInterface.GpsLongitudeRef.WEST);
+ if (latTag == null || longTag == null || latRefTag == null || longRefTag == null) {
+ return false;
+ }
+ setTag(latTag);
+ setTag(longTag);
+ setTag(latRefTag);
+ setTag(longRefTag);
+ return true;
+ }
+
+ /**
+ * Creates and sets the GPS timestamp tag.
+ *
+ * @param timestamp a GPS timestamp.
+ * @return true if success, false if could not be created or set.
+ */
+ public boolean addGpsDateTimeStampTag(long timestamp) {
+ ExifTag t = buildTag(TAG_GPS_DATE_STAMP, mGPSDateStampFormat.format(timestamp));
+ if (t == null) {
+ return false;
+ }
+ setTag(t);
+ mGPSTimeStampCalendar.setTimeInMillis(timestamp);
+ t = buildTag(TAG_GPS_TIME_STAMP, new Rational[] {
+ new Rational(mGPSTimeStampCalendar.get(Calendar.HOUR_OF_DAY), 1),
+ new Rational(mGPSTimeStampCalendar.get(Calendar.MINUTE), 1),
+ new Rational(mGPSTimeStampCalendar.get(Calendar.SECOND), 1)
+ });
+ if (t == null) {
+ return false;
+ }
+ setTag(t);
+ return true;
+ }
+
+ private static Rational[] toExifLatLong(double value) {
+ // convert to the format dd/1 mm/1 ssss/100
+ value = Math.abs(value);
+ int degrees = (int) value;
+ value = (value - degrees) * 60;
+ int minutes = (int) value;
+ value = (value - minutes) * 6000;
+ int seconds = (int) value;
+ return new Rational[] {
+ new Rational(degrees, 1), new Rational(minutes, 1), new Rational(seconds, 100)
+ };
+ }
+
+ private void doExifStreamIO(InputStream is, OutputStream os) throws IOException {
+ byte[] buf = new byte[1024];
+ int ret = is.read(buf, 0, 1024);
+ while (ret != -1) {
+ os.write(buf, 0, ret);
+ ret = is.read(buf, 0, 1024);
+ }
+ }
+
+ protected static void closeSilently(Closeable c) {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (Throwable e) {
+ // ignored
+ }
+ }
+ }
+
+ private SparseIntArray mTagInfo = null;
+
+ protected SparseIntArray getTagInfo() {
+ if (mTagInfo == null) {
+ mTagInfo = new SparseIntArray();
+ initTagInfo();
+ }
+ return mTagInfo;
+ }
+
+ private void initTagInfo() {
+ /**
+ * We put tag information in a 4-bytes integer. The first byte a bitmask
+ * representing the allowed IFDs of the tag, the second byte is the data
+ * type, and the last two byte are a short value indicating the default
+ * component count of this tag.
+ */
+ // IFD0 tags
+ int[] ifdAllowedIfds = {
+ IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1
+ };
+ int ifdFlags = getFlagsFromAllowedIfds(ifdAllowedIfds) << 24;
+ mTagInfo.put(ExifInterface.TAG_MAKE,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_IMAGE_WIDTH,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_IMAGE_LENGTH,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_BITS_PER_SAMPLE,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_COMPRESSION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_ORIENTATION, ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16
+ | 1);
+ mTagInfo.put(ExifInterface.TAG_SAMPLES_PER_PIXEL,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_PLANAR_CONFIGURATION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_Y_CB_CR_POSITIONING,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_X_RESOLUTION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_Y_RESOLUTION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_RESOLUTION_UNIT,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_STRIP_OFFSETS,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_ROWS_PER_STRIP,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_STRIP_BYTE_COUNTS,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_TRANSFER_FUNCTION,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 3 * 256);
+ mTagInfo.put(ExifInterface.TAG_WHITE_POINT,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_PRIMARY_CHROMATICITIES,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
+ mTagInfo.put(ExifInterface.TAG_Y_CB_CR_COEFFICIENTS,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_REFERENCE_BLACK_WHITE,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 6);
+ mTagInfo.put(ExifInterface.TAG_DATE_TIME,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | 20);
+ mTagInfo.put(ExifInterface.TAG_IMAGE_DESCRIPTION,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_MAKE,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_MODEL,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SOFTWARE,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_ARTIST,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_COPYRIGHT,
+ ifdFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_EXIF_IFD,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_IFD,
+ ifdFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ // IFD1 tags
+ int[] ifd1AllowedIfds = {
+ IfdId.TYPE_IFD_1
+ };
+ int ifdFlags1 = getFlagsFromAllowedIfds(ifd1AllowedIfds) << 24;
+ mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT,
+ ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
+ ifdFlags1 | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ // Exif tags
+ int[] exifAllowedIfds = {
+ IfdId.TYPE_IFD_EXIF
+ };
+ int exifFlags = getFlagsFromAllowedIfds(exifAllowedIfds) << 24;
+ mTagInfo.put(ExifInterface.TAG_EXIF_VERSION,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
+ mTagInfo.put(ExifInterface.TAG_FLASHPIX_VERSION,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
+ mTagInfo.put(ExifInterface.TAG_COLOR_SPACE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_COMPONENTS_CONFIGURATION,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 4);
+ mTagInfo.put(ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_PIXEL_X_DIMENSION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_PIXEL_Y_DIMENSION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_MAKER_NOTE,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_USER_COMMENT,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_RELATED_SOUND_FILE,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | 13);
+ mTagInfo.put(ExifInterface.TAG_DATE_TIME_ORIGINAL,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
+ mTagInfo.put(ExifInterface.TAG_DATE_TIME_DIGITIZED,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | 20);
+ mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_ORIGINAL,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SUB_SEC_TIME_DIGITIZED,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_IMAGE_UNIQUE_ID,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | 33);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_TIME,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_F_NUMBER,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_PROGRAM,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SPECTRAL_SENSITIVITY,
+ exifFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_ISO_SPEED_RATINGS,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_OECF,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SHUTTER_SPEED_VALUE,
+ exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_APERTURE_VALUE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_BRIGHTNESS_VALUE,
+ exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_BIAS_VALUE,
+ exifFlags | ExifTag.TYPE_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_MAX_APERTURE_VALUE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_METERING_MODE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_LIGHT_SOURCE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FLASH,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SUBJECT_AREA,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_FLASH_ENERGY,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SUBJECT_LOCATION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_INDEX,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SENSING_METHOD,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FILE_SOURCE,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SCENE_TYPE,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_CFA_PATTERN,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_CUSTOM_RENDERED,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_EXPOSURE_MODE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_WHITE_BALANCE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_DIGITAL_ZOOM_RATIO,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_FOCAL_LENGTH_IN_35_MM_FILE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SCENE_CAPTURE_TYPE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GAIN_CONTROL,
+ exifFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_CONTRAST,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SATURATION,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_SHARPNESS,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION,
+ exifFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_SUBJECT_DISTANCE_RANGE,
+ exifFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_INTEROPERABILITY_IFD, exifFlags
+ | ExifTag.TYPE_UNSIGNED_LONG << 16 | 1);
+ // GPS tag
+ int[] gpsAllowedIfds = {
+ IfdId.TYPE_IFD_GPS
+ };
+ int gpsFlags = getFlagsFromAllowedIfds(gpsAllowedIfds) << 24;
+ mTagInfo.put(ExifInterface.TAG_GPS_VERSION_ID,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 4);
+ mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_LATITUDE,
+ gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_GPS_LONGITUDE,
+ gpsFlags | ExifTag.TYPE_RATIONAL << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE_REF,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_BYTE << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_ALTITUDE,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_TIME_STAMP,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 3);
+ mTagInfo.put(ExifInterface.TAG_GPS_SATTELLITES,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_GPS_STATUS,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_MEASURE_MODE,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_DOP,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_SPEED_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_SPEED,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_TRACK_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_TRACK,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_IMG_DIRECTION,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_MAP_DATUM,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_LATITUDE,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_BEARING,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE_REF,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 2);
+ mTagInfo.put(ExifInterface.TAG_GPS_DEST_DISTANCE,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_RATIONAL << 16 | 1);
+ mTagInfo.put(ExifInterface.TAG_GPS_PROCESSING_METHOD,
+ gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_GPS_AREA_INFORMATION,
+ gpsFlags | ExifTag.TYPE_UNDEFINED << 16 | ExifTag.SIZE_UNDEFINED);
+ mTagInfo.put(ExifInterface.TAG_GPS_DATE_STAMP,
+ gpsFlags | ExifTag.TYPE_ASCII << 16 | 11);
+ mTagInfo.put(ExifInterface.TAG_GPS_DIFFERENTIAL,
+ gpsFlags | ExifTag.TYPE_UNSIGNED_SHORT << 16 | 11);
+ // Interoperability tag
+ int[] interopAllowedIfds = {
+ IfdId.TYPE_IFD_INTEROPERABILITY
+ };
+ int interopFlags = getFlagsFromAllowedIfds(interopAllowedIfds) << 24;
+ mTagInfo.put(TAG_INTEROPERABILITY_INDEX, interopFlags | ExifTag.TYPE_ASCII << 16
+ | ExifTag.SIZE_UNDEFINED);
+ }
+
+ protected static int getAllowedIfdFlagsFromInfo(int info) {
+ return info >>> 24;
+ }
+
+ protected static int[] getAllowedIfdsFromInfo(int info) {
+ int ifdFlags = getAllowedIfdFlagsFromInfo(info);
+ int[] ifds = IfdData.getIfds();
+ ArrayList<Integer> l = new ArrayList<Integer>();
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ int flag = (ifdFlags >> i) & 1;
+ if (flag == 1) {
+ l.add(ifds[i]);
+ }
+ }
+ if (l.size() <= 0) {
+ return null;
+ }
+ int[] ret = new int[l.size()];
+ int j = 0;
+ for (int i : l) {
+ ret[j++] = i;
+ }
+ return ret;
+ }
+
+ protected static boolean isIfdAllowed(int info, int ifd) {
+ int[] ifds = IfdData.getIfds();
+ int ifdFlags = getAllowedIfdFlagsFromInfo(info);
+ for (int i = 0; i < ifds.length; i++) {
+ if (ifd == ifds[i] && ((ifdFlags >> i) & 1) == 1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected static int getFlagsFromAllowedIfds(int[] allowedIfds) {
+ if (allowedIfds == null || allowedIfds.length == 0) {
+ return 0;
+ }
+ int flags = 0;
+ int[] ifds = IfdData.getIfds();
+ for (int i = 0; i < IfdId.TYPE_IFD_COUNT; i++) {
+ for (int j : allowedIfds) {
+ if (ifds[i] == j) {
+ flags |= 1 << i;
+ break;
+ }
+ }
+ }
+ return flags;
+ }
+
+ protected static short getTypeFromInfo(int info) {
+ return (short) ((info >> 16) & 0x0ff);
+ }
+
+ protected static int getComponentCountFromInfo(int info) {
+ return info & 0x0ffff;
+ }
+
+}
diff --git a/core/res/res/values-land/refs.xml b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
similarity index 62%
copy from core/res/res/values-land/refs.xml
copy to packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
index cda38cf..bf923ec 100644
--- a/core/res/res/values-land/refs.xml
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifInvalidFormatException.java
@@ -1,20 +1,23 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2013, The Android Open Source Project
+/*
+ * 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
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources>
\ No newline at end of file
+ */
+
+package com.android.gallery3d.exif;
+
+public class ExifInvalidFormatException extends Exception {
+ public ExifInvalidFormatException(String meg) {
+ super(meg);
+ }
+}
\ No newline at end of file
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifModifier.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifModifier.java
new file mode 100644
index 0000000..f00362b
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifModifier.java
@@ -0,0 +1,196 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+class ExifModifier {
+ public static final String TAG = "ExifModifier";
+ public static final boolean DEBUG = false;
+ private final ByteBuffer mByteBuffer;
+ private final ExifData mTagToModified;
+ private final List<TagOffset> mTagOffsets = new ArrayList<TagOffset>();
+ private final ExifInterface mInterface;
+ private int mOffsetBase;
+
+ private static class TagOffset {
+ final int mOffset;
+ final ExifTag mTag;
+
+ TagOffset(ExifTag tag, int offset) {
+ mTag = tag;
+ mOffset = offset;
+ }
+ }
+
+ protected ExifModifier(ByteBuffer byteBuffer, ExifInterface iRef) throws IOException,
+ ExifInvalidFormatException {
+ mByteBuffer = byteBuffer;
+ mOffsetBase = byteBuffer.position();
+ mInterface = iRef;
+ InputStream is = null;
+ try {
+ is = new ByteBufferInputStream(byteBuffer);
+ // Do not require any IFD;
+ ExifParser parser = ExifParser.parse(is, mInterface);
+ mTagToModified = new ExifData(parser.getByteOrder());
+ mOffsetBase += parser.getTiffStartPosition();
+ mByteBuffer.position(0);
+ } finally {
+ ExifInterface.closeSilently(is);
+ }
+ }
+
+ protected ByteOrder getByteOrder() {
+ return mTagToModified.getByteOrder();
+ }
+
+ protected boolean commit() throws IOException, ExifInvalidFormatException {
+ InputStream is = null;
+ try {
+ is = new ByteBufferInputStream(mByteBuffer);
+ int flag = 0;
+ IfdData[] ifdDatas = new IfdData[] {
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_0),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_1),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_EXIF),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY),
+ mTagToModified.getIfdData(IfdId.TYPE_IFD_GPS)
+ };
+
+ if (ifdDatas[IfdId.TYPE_IFD_0] != null) {
+ flag |= ExifParser.OPTION_IFD_0;
+ }
+ if (ifdDatas[IfdId.TYPE_IFD_1] != null) {
+ flag |= ExifParser.OPTION_IFD_1;
+ }
+ if (ifdDatas[IfdId.TYPE_IFD_EXIF] != null) {
+ flag |= ExifParser.OPTION_IFD_EXIF;
+ }
+ if (ifdDatas[IfdId.TYPE_IFD_GPS] != null) {
+ flag |= ExifParser.OPTION_IFD_GPS;
+ }
+ if (ifdDatas[IfdId.TYPE_IFD_INTEROPERABILITY] != null) {
+ flag |= ExifParser.OPTION_IFD_INTEROPERABILITY;
+ }
+
+ ExifParser parser = ExifParser.parse(is, flag, mInterface);
+ int event = parser.next();
+ IfdData currIfd = null;
+ while (event != ExifParser.EVENT_END) {
+ switch (event) {
+ case ExifParser.EVENT_START_OF_IFD:
+ currIfd = ifdDatas[parser.getCurrentIfd()];
+ if (currIfd == null) {
+ parser.skipRemainingTagsInCurrentIfd();
+ }
+ break;
+ case ExifParser.EVENT_NEW_TAG:
+ ExifTag oldTag = parser.getTag();
+ ExifTag newTag = currIfd.getTag(oldTag.getTagId());
+ if (newTag != null) {
+ if (newTag.getComponentCount() != oldTag.getComponentCount()
+ || newTag.getDataType() != oldTag.getDataType()) {
+ return false;
+ } else {
+ mTagOffsets.add(new TagOffset(newTag, oldTag.getOffset()));
+ currIfd.removeTag(oldTag.getTagId());
+ if (currIfd.getTagCount() == 0) {
+ parser.skipRemainingTagsInCurrentIfd();
+ }
+ }
+ }
+ break;
+ }
+ event = parser.next();
+ }
+ for (IfdData ifd : ifdDatas) {
+ if (ifd != null && ifd.getTagCount() > 0) {
+ return false;
+ }
+ }
+ modify();
+ } finally {
+ ExifInterface.closeSilently(is);
+ }
+ return true;
+ }
+
+ private void modify() {
+ mByteBuffer.order(getByteOrder());
+ for (TagOffset tagOffset : mTagOffsets) {
+ writeTagValue(tagOffset.mTag, tagOffset.mOffset);
+ }
+ }
+
+ private void writeTagValue(ExifTag tag, int offset) {
+ if (DEBUG) {
+ Log.v(TAG, "modifying tag to: \n" + tag.toString());
+ Log.v(TAG, "at offset: " + offset);
+ }
+ mByteBuffer.position(offset + mOffsetBase);
+ switch (tag.getDataType()) {
+ case ExifTag.TYPE_ASCII:
+ byte buf[] = tag.getStringByte();
+ if (buf.length == tag.getComponentCount()) {
+ buf[buf.length - 1] = 0;
+ mByteBuffer.put(buf);
+ } else {
+ mByteBuffer.put(buf);
+ mByteBuffer.put((byte) 0);
+ }
+ break;
+ case ExifTag.TYPE_LONG:
+ case ExifTag.TYPE_UNSIGNED_LONG:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ mByteBuffer.putInt((int) tag.getValueAt(i));
+ }
+ break;
+ case ExifTag.TYPE_RATIONAL:
+ case ExifTag.TYPE_UNSIGNED_RATIONAL:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ Rational v = tag.getRational(i);
+ mByteBuffer.putInt((int) v.getNumerator());
+ mByteBuffer.putInt((int) v.getDenominator());
+ }
+ break;
+ case ExifTag.TYPE_UNDEFINED:
+ case ExifTag.TYPE_UNSIGNED_BYTE:
+ buf = new byte[tag.getComponentCount()];
+ tag.getBytes(buf);
+ mByteBuffer.put(buf);
+ break;
+ case ExifTag.TYPE_UNSIGNED_SHORT:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ mByteBuffer.putShort((short) tag.getValueAt(i));
+ }
+ break;
+ }
+ }
+
+ public void modifyTag(ExifTag tag) {
+ mTagToModified.addTag(tag);
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifOutputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifOutputStream.java
new file mode 100644
index 0000000..7ca05f2e
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifOutputStream.java
@@ -0,0 +1,518 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+
+/**
+ * This class provides a way to replace the Exif header of a JPEG image.
+ * <p>
+ * Below is an example of writing EXIF data into a file
+ *
+ * <pre>
+ * public static void writeExif(byte[] jpeg, ExifData exif, String path) {
+ * OutputStream os = null;
+ * try {
+ * os = new FileOutputStream(path);
+ * ExifOutputStream eos = new ExifOutputStream(os);
+ * // Set the exif header
+ * eos.setExifData(exif);
+ * // Write the original jpeg out, the header will be add into the file.
+ * eos.write(jpeg);
+ * } catch (FileNotFoundException e) {
+ * e.printStackTrace();
+ * } catch (IOException e) {
+ * e.printStackTrace();
+ * } finally {
+ * if (os != null) {
+ * try {
+ * os.close();
+ * } catch (IOException e) {
+ * e.printStackTrace();
+ * }
+ * }
+ * }
+ * }
+ * </pre>
+ */
+class ExifOutputStream extends FilterOutputStream {
+ private static final String TAG = "ExifOutputStream";
+ private static final boolean DEBUG = false;
+ private static final int STREAMBUFFER_SIZE = 0x00010000; // 64Kb
+
+ private static final int STATE_SOI = 0;
+ private static final int STATE_FRAME_HEADER = 1;
+ private static final int STATE_JPEG_DATA = 2;
+
+ private static final int EXIF_HEADER = 0x45786966;
+ private static final short TIFF_HEADER = 0x002A;
+ private static final short TIFF_BIG_ENDIAN = 0x4d4d;
+ private static final short TIFF_LITTLE_ENDIAN = 0x4949;
+ private static final short TAG_SIZE = 12;
+ private static final short TIFF_HEADER_SIZE = 8;
+ private static final int MAX_EXIF_SIZE = 65535;
+
+ private ExifData mExifData;
+ private int mState = STATE_SOI;
+ private int mByteToSkip;
+ private int mByteToCopy;
+ private byte[] mSingleByteArray = new byte[1];
+ private ByteBuffer mBuffer = ByteBuffer.allocate(4);
+ private final ExifInterface mInterface;
+
+ protected ExifOutputStream(OutputStream ou, ExifInterface iRef) {
+ super(new BufferedOutputStream(ou, STREAMBUFFER_SIZE));
+ mInterface = iRef;
+ }
+
+ /**
+ * Sets the ExifData to be written into the JPEG file. Should be called
+ * before writing image data.
+ */
+ protected void setExifData(ExifData exifData) {
+ mExifData = exifData;
+ }
+
+ /**
+ * Gets the Exif header to be written into the JPEF file.
+ */
+ protected ExifData getExifData() {
+ return mExifData;
+ }
+
+ private int requestByteToBuffer(int requestByteCount, byte[] buffer
+ , int offset, int length) {
+ int byteNeeded = requestByteCount - mBuffer.position();
+ int byteToRead = length > byteNeeded ? byteNeeded : length;
+ mBuffer.put(buffer, offset, byteToRead);
+ return byteToRead;
+ }
+
+ /**
+ * Writes the image out. The input data should be a valid JPEG format. After
+ * writing, it's Exif header will be replaced by the given header.
+ */
+ @Override
+ public void write(byte[] buffer, int offset, int length) throws IOException {
+ while ((mByteToSkip > 0 || mByteToCopy > 0 || mState != STATE_JPEG_DATA)
+ && length > 0) {
+ if (mByteToSkip > 0) {
+ int byteToProcess = length > mByteToSkip ? mByteToSkip : length;
+ length -= byteToProcess;
+ mByteToSkip -= byteToProcess;
+ offset += byteToProcess;
+ }
+ if (mByteToCopy > 0) {
+ int byteToProcess = length > mByteToCopy ? mByteToCopy : length;
+ out.write(buffer, offset, byteToProcess);
+ length -= byteToProcess;
+ mByteToCopy -= byteToProcess;
+ offset += byteToProcess;
+ }
+ if (length == 0) {
+ return;
+ }
+ switch (mState) {
+ case STATE_SOI:
+ int byteRead = requestByteToBuffer(2, buffer, offset, length);
+ offset += byteRead;
+ length -= byteRead;
+ if (mBuffer.position() < 2) {
+ return;
+ }
+ mBuffer.rewind();
+ if (mBuffer.getShort() != JpegHeader.SOI) {
+ throw new IOException("Not a valid jpeg image, cannot write exif");
+ }
+ out.write(mBuffer.array(), 0, 2);
+ mState = STATE_FRAME_HEADER;
+ mBuffer.rewind();
+ writeExifData();
+ break;
+ case STATE_FRAME_HEADER:
+ // We ignore the APP1 segment and copy all other segments
+ // until SOF tag.
+ byteRead = requestByteToBuffer(4, buffer, offset, length);
+ offset += byteRead;
+ length -= byteRead;
+ // Check if this image data doesn't contain SOF.
+ if (mBuffer.position() == 2) {
+ short tag = mBuffer.getShort();
+ if (tag == JpegHeader.EOI) {
+ out.write(mBuffer.array(), 0, 2);
+ mBuffer.rewind();
+ }
+ }
+ if (mBuffer.position() < 4) {
+ return;
+ }
+ mBuffer.rewind();
+ short marker = mBuffer.getShort();
+ if (marker == JpegHeader.APP1) {
+ mByteToSkip = (mBuffer.getShort() & 0x0000ffff) - 2;
+ mState = STATE_JPEG_DATA;
+ } else if (!JpegHeader.isSofMarker(marker)) {
+ out.write(mBuffer.array(), 0, 4);
+ mByteToCopy = (mBuffer.getShort() & 0x0000ffff) - 2;
+ } else {
+ out.write(mBuffer.array(), 0, 4);
+ mState = STATE_JPEG_DATA;
+ }
+ mBuffer.rewind();
+ }
+ }
+ if (length > 0) {
+ out.write(buffer, offset, length);
+ }
+ }
+
+ /**
+ * Writes the one bytes out. The input data should be a valid JPEG format.
+ * After writing, it's Exif header will be replaced by the given header.
+ */
+ @Override
+ public void write(int oneByte) throws IOException {
+ mSingleByteArray[0] = (byte) (0xff & oneByte);
+ write(mSingleByteArray);
+ }
+
+ /**
+ * Equivalent to calling write(buffer, 0, buffer.length).
+ */
+ @Override
+ public void write(byte[] buffer) throws IOException {
+ write(buffer, 0, buffer.length);
+ }
+
+ private void writeExifData() throws IOException {
+ if (mExifData == null) {
+ return;
+ }
+ if (DEBUG) {
+ Log.v(TAG, "Writing exif data...");
+ }
+ ArrayList<ExifTag> nullTags = stripNullValueTags(mExifData);
+ createRequiredIfdAndTag();
+ int exifSize = calculateAllOffset();
+ if (exifSize + 8 > MAX_EXIF_SIZE) {
+ throw new IOException("Exif header is too large (>64Kb)");
+ }
+ OrderedDataOutputStream dataOutputStream = new OrderedDataOutputStream(out);
+ dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+ dataOutputStream.writeShort(JpegHeader.APP1);
+ dataOutputStream.writeShort((short) (exifSize + 8));
+ dataOutputStream.writeInt(EXIF_HEADER);
+ dataOutputStream.writeShort((short) 0x0000);
+ if (mExifData.getByteOrder() == ByteOrder.BIG_ENDIAN) {
+ dataOutputStream.writeShort(TIFF_BIG_ENDIAN);
+ } else {
+ dataOutputStream.writeShort(TIFF_LITTLE_ENDIAN);
+ }
+ dataOutputStream.setByteOrder(mExifData.getByteOrder());
+ dataOutputStream.writeShort(TIFF_HEADER);
+ dataOutputStream.writeInt(8);
+ writeAllTags(dataOutputStream);
+ writeThumbnail(dataOutputStream);
+ for (ExifTag t : nullTags) {
+ mExifData.addTag(t);
+ }
+ }
+
+ private ArrayList<ExifTag> stripNullValueTags(ExifData data) {
+ ArrayList<ExifTag> nullTags = new ArrayList<ExifTag>();
+ for(ExifTag t : data.getAllTags()) {
+ if (t.getValue() == null && !ExifInterface.isOffsetTag(t.getTagId())) {
+ data.removeTag(t.getTagId(), t.getIfd());
+ nullTags.add(t);
+ }
+ }
+ return nullTags;
+ }
+
+ private void writeThumbnail(OrderedDataOutputStream dataOutputStream) throws IOException {
+ if (mExifData.hasCompressedThumbnail()) {
+ dataOutputStream.write(mExifData.getCompressedThumbnail());
+ } else if (mExifData.hasUncompressedStrip()) {
+ for (int i = 0; i < mExifData.getStripCount(); i++) {
+ dataOutputStream.write(mExifData.getStrip(i));
+ }
+ }
+ }
+
+ private void writeAllTags(OrderedDataOutputStream dataOutputStream) throws IOException {
+ writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_0), dataOutputStream);
+ writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_EXIF), dataOutputStream);
+ IfdData interoperabilityIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+ if (interoperabilityIfd != null) {
+ writeIfd(interoperabilityIfd, dataOutputStream);
+ }
+ IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
+ if (gpsIfd != null) {
+ writeIfd(gpsIfd, dataOutputStream);
+ }
+ IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
+ if (ifd1 != null) {
+ writeIfd(mExifData.getIfdData(IfdId.TYPE_IFD_1), dataOutputStream);
+ }
+ }
+
+ private void writeIfd(IfdData ifd, OrderedDataOutputStream dataOutputStream)
+ throws IOException {
+ ExifTag[] tags = ifd.getAllTags();
+ dataOutputStream.writeShort((short) tags.length);
+ for (ExifTag tag : tags) {
+ dataOutputStream.writeShort(tag.getTagId());
+ dataOutputStream.writeShort(tag.getDataType());
+ dataOutputStream.writeInt(tag.getComponentCount());
+ if (DEBUG) {
+ Log.v(TAG, "\n" + tag.toString());
+ }
+ if (tag.getDataSize() > 4) {
+ dataOutputStream.writeInt(tag.getOffset());
+ } else {
+ ExifOutputStream.writeTagValue(tag, dataOutputStream);
+ for (int i = 0, n = 4 - tag.getDataSize(); i < n; i++) {
+ dataOutputStream.write(0);
+ }
+ }
+ }
+ dataOutputStream.writeInt(ifd.getOffsetToNextIfd());
+ for (ExifTag tag : tags) {
+ if (tag.getDataSize() > 4) {
+ ExifOutputStream.writeTagValue(tag, dataOutputStream);
+ }
+ }
+ }
+
+ private int calculateOffsetOfIfd(IfdData ifd, int offset) {
+ offset += 2 + ifd.getTagCount() * TAG_SIZE + 4;
+ ExifTag[] tags = ifd.getAllTags();
+ for (ExifTag tag : tags) {
+ if (tag.getDataSize() > 4) {
+ tag.setOffset(offset);
+ offset += tag.getDataSize();
+ }
+ }
+ return offset;
+ }
+
+ private void createRequiredIfdAndTag() throws IOException {
+ // IFD0 is required for all file
+ IfdData ifd0 = mExifData.getIfdData(IfdId.TYPE_IFD_0);
+ if (ifd0 == null) {
+ ifd0 = new IfdData(IfdId.TYPE_IFD_0);
+ mExifData.addIfdData(ifd0);
+ }
+ ExifTag exifOffsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_EXIF_IFD);
+ if (exifOffsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_EXIF_IFD);
+ }
+ ifd0.setTag(exifOffsetTag);
+
+ // Exif IFD is required for all files.
+ IfdData exifIfd = mExifData.getIfdData(IfdId.TYPE_IFD_EXIF);
+ if (exifIfd == null) {
+ exifIfd = new IfdData(IfdId.TYPE_IFD_EXIF);
+ mExifData.addIfdData(exifIfd);
+ }
+
+ // GPS IFD
+ IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
+ if (gpsIfd != null) {
+ ExifTag gpsOffsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_GPS_IFD);
+ if (gpsOffsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_GPS_IFD);
+ }
+ ifd0.setTag(gpsOffsetTag);
+ }
+
+ // Interoperability IFD
+ IfdData interIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+ if (interIfd != null) {
+ ExifTag interOffsetTag = mInterface
+ .buildUninitializedTag(ExifInterface.TAG_INTEROPERABILITY_IFD);
+ if (interOffsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_INTEROPERABILITY_IFD);
+ }
+ exifIfd.setTag(interOffsetTag);
+ }
+
+ IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
+
+ // thumbnail
+ if (mExifData.hasCompressedThumbnail()) {
+
+ if (ifd1 == null) {
+ ifd1 = new IfdData(IfdId.TYPE_IFD_1);
+ mExifData.addIfdData(ifd1);
+ }
+
+ ExifTag offsetTag = mInterface
+ .buildUninitializedTag(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
+ if (offsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
+ }
+
+ ifd1.setTag(offsetTag);
+ ExifTag lengthTag = mInterface
+ .buildUninitializedTag(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+ if (lengthTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+ }
+
+ lengthTag.setValue(mExifData.getCompressedThumbnail().length);
+ ifd1.setTag(lengthTag);
+
+ // Get rid of tags for uncompressed if they exist.
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS));
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS));
+ } else if (mExifData.hasUncompressedStrip()) {
+ if (ifd1 == null) {
+ ifd1 = new IfdData(IfdId.TYPE_IFD_1);
+ mExifData.addIfdData(ifd1);
+ }
+ int stripCount = mExifData.getStripCount();
+ ExifTag offsetTag = mInterface.buildUninitializedTag(ExifInterface.TAG_STRIP_OFFSETS);
+ if (offsetTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_STRIP_OFFSETS);
+ }
+ ExifTag lengthTag = mInterface
+ .buildUninitializedTag(ExifInterface.TAG_STRIP_BYTE_COUNTS);
+ if (lengthTag == null) {
+ throw new IOException("No definition for crucial exif tag: "
+ + ExifInterface.TAG_STRIP_BYTE_COUNTS);
+ }
+ long[] lengths = new long[stripCount];
+ for (int i = 0; i < mExifData.getStripCount(); i++) {
+ lengths[i] = mExifData.getStrip(i).length;
+ }
+ lengthTag.setValue(lengths);
+ ifd1.setTag(offsetTag);
+ ifd1.setTag(lengthTag);
+ // Get rid of tags for compressed if they exist.
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT));
+ ifd1.removeTag(ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
+ } else if (ifd1 != null) {
+ // Get rid of offset and length tags if there is no thumbnail.
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS));
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS));
+ ifd1.removeTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT));
+ ifd1.removeTag(ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH));
+ }
+ }
+
+ private int calculateAllOffset() {
+ int offset = TIFF_HEADER_SIZE;
+ IfdData ifd0 = mExifData.getIfdData(IfdId.TYPE_IFD_0);
+ offset = calculateOffsetOfIfd(ifd0, offset);
+ ifd0.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_EXIF_IFD)).setValue(offset);
+
+ IfdData exifIfd = mExifData.getIfdData(IfdId.TYPE_IFD_EXIF);
+ offset = calculateOffsetOfIfd(exifIfd, offset);
+
+ IfdData interIfd = mExifData.getIfdData(IfdId.TYPE_IFD_INTEROPERABILITY);
+ if (interIfd != null) {
+ exifIfd.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD))
+ .setValue(offset);
+ offset = calculateOffsetOfIfd(interIfd, offset);
+ }
+
+ IfdData gpsIfd = mExifData.getIfdData(IfdId.TYPE_IFD_GPS);
+ if (gpsIfd != null) {
+ ifd0.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD)).setValue(offset);
+ offset = calculateOffsetOfIfd(gpsIfd, offset);
+ }
+
+ IfdData ifd1 = mExifData.getIfdData(IfdId.TYPE_IFD_1);
+ if (ifd1 != null) {
+ ifd0.setOffsetToNextIfd(offset);
+ offset = calculateOffsetOfIfd(ifd1, offset);
+ }
+
+ // thumbnail
+ if (mExifData.hasCompressedThumbnail()) {
+ ifd1.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT))
+ .setValue(offset);
+ offset += mExifData.getCompressedThumbnail().length;
+ } else if (mExifData.hasUncompressedStrip()) {
+ int stripCount = mExifData.getStripCount();
+ long[] offsets = new long[stripCount];
+ for (int i = 0; i < mExifData.getStripCount(); i++) {
+ offsets[i] = offset;
+ offset += mExifData.getStrip(i).length;
+ }
+ ifd1.getTag(ExifInterface.getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS)).setValue(
+ offsets);
+ }
+ return offset;
+ }
+
+ static void writeTagValue(ExifTag tag, OrderedDataOutputStream dataOutputStream)
+ throws IOException {
+ switch (tag.getDataType()) {
+ case ExifTag.TYPE_ASCII:
+ byte buf[] = tag.getStringByte();
+ if (buf.length == tag.getComponentCount()) {
+ buf[buf.length - 1] = 0;
+ dataOutputStream.write(buf);
+ } else {
+ dataOutputStream.write(buf);
+ dataOutputStream.write(0);
+ }
+ break;
+ case ExifTag.TYPE_LONG:
+ case ExifTag.TYPE_UNSIGNED_LONG:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ dataOutputStream.writeInt((int) tag.getValueAt(i));
+ }
+ break;
+ case ExifTag.TYPE_RATIONAL:
+ case ExifTag.TYPE_UNSIGNED_RATIONAL:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ dataOutputStream.writeRational(tag.getRational(i));
+ }
+ break;
+ case ExifTag.TYPE_UNDEFINED:
+ case ExifTag.TYPE_UNSIGNED_BYTE:
+ buf = new byte[tag.getComponentCount()];
+ tag.getBytes(buf);
+ dataOutputStream.write(buf);
+ break;
+ case ExifTag.TYPE_UNSIGNED_SHORT:
+ for (int i = 0, n = tag.getComponentCount(); i < n; i++) {
+ dataOutputStream.writeShort((short) tag.getValueAt(i));
+ }
+ break;
+ }
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java
new file mode 100644
index 0000000..5467d42
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifParser.java
@@ -0,0 +1,916 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+/**
+ * This class provides a low-level EXIF parsing API. Given a JPEG format
+ * InputStream, the caller can request which IFD's to read via
+ * {@link #parse(InputStream, int)} with given options.
+ * <p>
+ * Below is an example of getting EXIF data from IFD 0 and EXIF IFD using the
+ * parser.
+ *
+ * <pre>
+ * void parse() {
+ * ExifParser parser = ExifParser.parse(mImageInputStream,
+ * ExifParser.OPTION_IFD_0 | ExifParser.OPTIONS_IFD_EXIF);
+ * int event = parser.next();
+ * while (event != ExifParser.EVENT_END) {
+ * switch (event) {
+ * case ExifParser.EVENT_START_OF_IFD:
+ * break;
+ * case ExifParser.EVENT_NEW_TAG:
+ * ExifTag tag = parser.getTag();
+ * if (!tag.hasValue()) {
+ * parser.registerForTagValue(tag);
+ * } else {
+ * processTag(tag);
+ * }
+ * break;
+ * case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
+ * tag = parser.getTag();
+ * if (tag.getDataType() != ExifTag.TYPE_UNDEFINED) {
+ * processTag(tag);
+ * }
+ * break;
+ * }
+ * event = parser.next();
+ * }
+ * }
+ *
+ * void processTag(ExifTag tag) {
+ * // process the tag as you like.
+ * }
+ * </pre>
+ */
+class ExifParser {
+ private static final boolean LOGV = false;
+ private static final String TAG = "ExifParser";
+ /**
+ * When the parser reaches a new IFD area. Call {@link #getCurrentIfd()} to
+ * know which IFD we are in.
+ */
+ public static final int EVENT_START_OF_IFD = 0;
+ /**
+ * When the parser reaches a new tag. Call {@link #getTag()}to get the
+ * corresponding tag.
+ */
+ public static final int EVENT_NEW_TAG = 1;
+ /**
+ * When the parser reaches the value area of tag that is registered by
+ * {@link #registerForTagValue(ExifTag)} previously. Call {@link #getTag()}
+ * to get the corresponding tag.
+ */
+ public static final int EVENT_VALUE_OF_REGISTERED_TAG = 2;
+
+ /**
+ * When the parser reaches the compressed image area.
+ */
+ public static final int EVENT_COMPRESSED_IMAGE = 3;
+ /**
+ * When the parser reaches the uncompressed image strip. Call
+ * {@link #getStripIndex()} to get the index of the strip.
+ *
+ * @see #getStripIndex()
+ * @see #getStripCount()
+ */
+ public static final int EVENT_UNCOMPRESSED_STRIP = 4;
+ /**
+ * When there is nothing more to parse.
+ */
+ public static final int EVENT_END = 5;
+
+ /**
+ * Option bit to request to parse IFD0.
+ */
+ public static final int OPTION_IFD_0 = 1 << 0;
+ /**
+ * Option bit to request to parse IFD1.
+ */
+ public static final int OPTION_IFD_1 = 1 << 1;
+ /**
+ * Option bit to request to parse Exif-IFD.
+ */
+ public static final int OPTION_IFD_EXIF = 1 << 2;
+ /**
+ * Option bit to request to parse GPS-IFD.
+ */
+ public static final int OPTION_IFD_GPS = 1 << 3;
+ /**
+ * Option bit to request to parse Interoperability-IFD.
+ */
+ public static final int OPTION_IFD_INTEROPERABILITY = 1 << 4;
+ /**
+ * Option bit to request to parse thumbnail.
+ */
+ public static final int OPTION_THUMBNAIL = 1 << 5;
+
+ protected static final int EXIF_HEADER = 0x45786966; // EXIF header "Exif"
+ protected static final short EXIF_HEADER_TAIL = (short) 0x0000; // EXIF header in APP1
+
+ // TIFF header
+ protected static final short LITTLE_ENDIAN_TAG = (short) 0x4949; // "II"
+ protected static final short BIG_ENDIAN_TAG = (short) 0x4d4d; // "MM"
+ protected static final short TIFF_HEADER_TAIL = 0x002A;
+
+ protected static final int TAG_SIZE = 12;
+ protected static final int OFFSET_SIZE = 2;
+
+ private static final Charset US_ASCII = Charset.forName("US-ASCII");
+
+ protected static final int DEFAULT_IFD0_OFFSET = 8;
+
+ private final CountedDataInputStream mTiffStream;
+ private final int mOptions;
+ private int mIfdStartOffset = 0;
+ private int mNumOfTagInIfd = 0;
+ private int mIfdType;
+ private ExifTag mTag;
+ private ImageEvent mImageEvent;
+ private int mStripCount;
+ private ExifTag mStripSizeTag;
+ private ExifTag mJpegSizeTag;
+ private boolean mNeedToParseOffsetsInCurrentIfd;
+ private boolean mContainExifData = false;
+ private int mApp1End;
+ private int mOffsetToApp1EndFromSOF = 0;
+ private byte[] mDataAboveIfd0;
+ private int mIfd0Position;
+ private int mTiffStartPosition;
+ private final ExifInterface mInterface;
+
+ private static final short TAG_EXIF_IFD = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_EXIF_IFD);
+ private static final short TAG_GPS_IFD = ExifInterface.getTrueTagKey(ExifInterface.TAG_GPS_IFD);
+ private static final short TAG_INTEROPERABILITY_IFD = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_INTEROPERABILITY_IFD);
+ private static final short TAG_JPEG_INTERCHANGE_FORMAT = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT);
+ private static final short TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
+ private static final short TAG_STRIP_OFFSETS = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_STRIP_OFFSETS);
+ private static final short TAG_STRIP_BYTE_COUNTS = ExifInterface
+ .getTrueTagKey(ExifInterface.TAG_STRIP_BYTE_COUNTS);
+
+ private final TreeMap<Integer, Object> mCorrespondingEvent = new TreeMap<Integer, Object>();
+
+ private boolean isIfdRequested(int ifdType) {
+ switch (ifdType) {
+ case IfdId.TYPE_IFD_0:
+ return (mOptions & OPTION_IFD_0) != 0;
+ case IfdId.TYPE_IFD_1:
+ return (mOptions & OPTION_IFD_1) != 0;
+ case IfdId.TYPE_IFD_EXIF:
+ return (mOptions & OPTION_IFD_EXIF) != 0;
+ case IfdId.TYPE_IFD_GPS:
+ return (mOptions & OPTION_IFD_GPS) != 0;
+ case IfdId.TYPE_IFD_INTEROPERABILITY:
+ return (mOptions & OPTION_IFD_INTEROPERABILITY) != 0;
+ }
+ return false;
+ }
+
+ private boolean isThumbnailRequested() {
+ return (mOptions & OPTION_THUMBNAIL) != 0;
+ }
+
+ private ExifParser(InputStream inputStream, int options, ExifInterface iRef)
+ throws IOException, ExifInvalidFormatException {
+ if (inputStream == null) {
+ throw new IOException("Null argument inputStream to ExifParser");
+ }
+ if (LOGV) {
+ Log.v(TAG, "Reading exif...");
+ }
+ mInterface = iRef;
+ mContainExifData = seekTiffData(inputStream);
+ mTiffStream = new CountedDataInputStream(inputStream);
+ mOptions = options;
+ if (!mContainExifData) {
+ return;
+ }
+
+ parseTiffHeader();
+ long offset = mTiffStream.readUnsignedInt();
+ if (offset > Integer.MAX_VALUE) {
+ throw new ExifInvalidFormatException("Invalid offset " + offset);
+ }
+ mIfd0Position = (int) offset;
+ mIfdType = IfdId.TYPE_IFD_0;
+ if (isIfdRequested(IfdId.TYPE_IFD_0) || needToParseOffsetsInCurrentIfd()) {
+ registerIfd(IfdId.TYPE_IFD_0, offset);
+ if (offset != DEFAULT_IFD0_OFFSET) {
+ mDataAboveIfd0 = new byte[(int) offset - DEFAULT_IFD0_OFFSET];
+ read(mDataAboveIfd0);
+ }
+ }
+ }
+
+ /**
+ * Parses the the given InputStream with the given options
+ *
+ * @exception IOException
+ * @exception ExifInvalidFormatException
+ */
+ protected static ExifParser parse(InputStream inputStream, int options, ExifInterface iRef)
+ throws IOException, ExifInvalidFormatException {
+ return new ExifParser(inputStream, options, iRef);
+ }
+
+ /**
+ * Parses the the given InputStream with default options; that is, every IFD
+ * and thumbnaill will be parsed.
+ *
+ * @exception IOException
+ * @exception ExifInvalidFormatException
+ * @see #parse(InputStream, int)
+ */
+ protected static ExifParser parse(InputStream inputStream, ExifInterface iRef)
+ throws IOException, ExifInvalidFormatException {
+ return new ExifParser(inputStream, OPTION_IFD_0 | OPTION_IFD_1
+ | OPTION_IFD_EXIF | OPTION_IFD_GPS | OPTION_IFD_INTEROPERABILITY
+ | OPTION_THUMBNAIL, iRef);
+ }
+
+ /**
+ * Moves the parser forward and returns the next parsing event
+ *
+ * @exception IOException
+ * @exception ExifInvalidFormatException
+ * @see #EVENT_START_OF_IFD
+ * @see #EVENT_NEW_TAG
+ * @see #EVENT_VALUE_OF_REGISTERED_TAG
+ * @see #EVENT_COMPRESSED_IMAGE
+ * @see #EVENT_UNCOMPRESSED_STRIP
+ * @see #EVENT_END
+ */
+ protected int next() throws IOException, ExifInvalidFormatException {
+ if (!mContainExifData) {
+ return EVENT_END;
+ }
+ int offset = mTiffStream.getReadByteCount();
+ int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
+ if (offset < endOfTags) {
+ mTag = readTag();
+ if (mTag == null) {
+ return next();
+ }
+ if (mNeedToParseOffsetsInCurrentIfd) {
+ checkOffsetOrImageTag(mTag);
+ }
+ return EVENT_NEW_TAG;
+ } else if (offset == endOfTags) {
+ // There is a link to ifd1 at the end of ifd0
+ if (mIfdType == IfdId.TYPE_IFD_0) {
+ long ifdOffset = readUnsignedLong();
+ if (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested()) {
+ if (ifdOffset != 0) {
+ registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
+ }
+ }
+ } else {
+ int offsetSize = 4;
+ // Some camera models use invalid length of the offset
+ if (mCorrespondingEvent.size() > 0) {
+ offsetSize = mCorrespondingEvent.firstEntry().getKey() -
+ mTiffStream.getReadByteCount();
+ }
+ if (offsetSize < 4) {
+ Log.w(TAG, "Invalid size of link to next IFD: " + offsetSize);
+ } else {
+ long ifdOffset = readUnsignedLong();
+ if (ifdOffset != 0) {
+ Log.w(TAG, "Invalid link to next IFD: " + ifdOffset);
+ }
+ }
+ }
+ }
+ while (mCorrespondingEvent.size() != 0) {
+ Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
+ Object event = entry.getValue();
+ try {
+ skipTo(entry.getKey());
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to skip to data at: " + entry.getKey() +
+ " for " + event.getClass().getName() + ", the file may be broken.");
+ continue;
+ }
+ if (event instanceof IfdEvent) {
+ mIfdType = ((IfdEvent) event).ifd;
+ mNumOfTagInIfd = mTiffStream.readUnsignedShort();
+ mIfdStartOffset = entry.getKey();
+
+ if (mNumOfTagInIfd * TAG_SIZE + mIfdStartOffset + OFFSET_SIZE > mApp1End) {
+ Log.w(TAG, "Invalid size of IFD " + mIfdType);
+ return EVENT_END;
+ }
+
+ mNeedToParseOffsetsInCurrentIfd = needToParseOffsetsInCurrentIfd();
+ if (((IfdEvent) event).isRequested) {
+ return EVENT_START_OF_IFD;
+ } else {
+ skipRemainingTagsInCurrentIfd();
+ }
+ } else if (event instanceof ImageEvent) {
+ mImageEvent = (ImageEvent) event;
+ return mImageEvent.type;
+ } else {
+ ExifTagEvent tagEvent = (ExifTagEvent) event;
+ mTag = tagEvent.tag;
+ if (mTag.getDataType() != ExifTag.TYPE_UNDEFINED) {
+ readFullTagValue(mTag);
+ checkOffsetOrImageTag(mTag);
+ }
+ if (tagEvent.isRequested) {
+ return EVENT_VALUE_OF_REGISTERED_TAG;
+ }
+ }
+ }
+ return EVENT_END;
+ }
+
+ /**
+ * Skips the tags area of current IFD, if the parser is not in the tag area,
+ * nothing will happen.
+ *
+ * @throws IOException
+ * @throws ExifInvalidFormatException
+ */
+ protected void skipRemainingTagsInCurrentIfd() throws IOException, ExifInvalidFormatException {
+ int endOfTags = mIfdStartOffset + OFFSET_SIZE + TAG_SIZE * mNumOfTagInIfd;
+ int offset = mTiffStream.getReadByteCount();
+ if (offset > endOfTags) {
+ return;
+ }
+ if (mNeedToParseOffsetsInCurrentIfd) {
+ while (offset < endOfTags) {
+ mTag = readTag();
+ offset += TAG_SIZE;
+ if (mTag == null) {
+ continue;
+ }
+ checkOffsetOrImageTag(mTag);
+ }
+ } else {
+ skipTo(endOfTags);
+ }
+ long ifdOffset = readUnsignedLong();
+ // For ifd0, there is a link to ifd1 in the end of all tags
+ if (mIfdType == IfdId.TYPE_IFD_0
+ && (isIfdRequested(IfdId.TYPE_IFD_1) || isThumbnailRequested())) {
+ if (ifdOffset > 0) {
+ registerIfd(IfdId.TYPE_IFD_1, ifdOffset);
+ }
+ }
+ }
+
+ private boolean needToParseOffsetsInCurrentIfd() {
+ switch (mIfdType) {
+ case IfdId.TYPE_IFD_0:
+ return isIfdRequested(IfdId.TYPE_IFD_EXIF) || isIfdRequested(IfdId.TYPE_IFD_GPS)
+ || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)
+ || isIfdRequested(IfdId.TYPE_IFD_1);
+ case IfdId.TYPE_IFD_1:
+ return isThumbnailRequested();
+ case IfdId.TYPE_IFD_EXIF:
+ // The offset to interoperability IFD is located in Exif IFD
+ return isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY);
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * If {@link #next()} return {@link #EVENT_NEW_TAG} or
+ * {@link #EVENT_VALUE_OF_REGISTERED_TAG}, call this function to get the
+ * corresponding tag.
+ * <p>
+ * For {@link #EVENT_NEW_TAG}, the tag may not contain the value if the size
+ * of the value is greater than 4 bytes. One should call
+ * {@link ExifTag#hasValue()} to check if the tag contains value. If there
+ * is no value,call {@link #registerForTagValue(ExifTag)} to have the parser
+ * emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
+ * pointed by the offset.
+ * <p>
+ * When {@link #EVENT_VALUE_OF_REGISTERED_TAG} is emitted, the value of the
+ * tag will have already been read except for tags of undefined type. For
+ * tags of undefined type, call one of the read methods to get the value.
+ *
+ * @see #registerForTagValue(ExifTag)
+ * @see #read(byte[])
+ * @see #read(byte[], int, int)
+ * @see #readLong()
+ * @see #readRational()
+ * @see #readString(int)
+ * @see #readString(int, Charset)
+ */
+ protected ExifTag getTag() {
+ return mTag;
+ }
+
+ /**
+ * Gets number of tags in the current IFD area.
+ */
+ protected int getTagCountInCurrentIfd() {
+ return mNumOfTagInIfd;
+ }
+
+ /**
+ * Gets the ID of current IFD.
+ *
+ * @see IfdId#TYPE_IFD_0
+ * @see IfdId#TYPE_IFD_1
+ * @see IfdId#TYPE_IFD_GPS
+ * @see IfdId#TYPE_IFD_INTEROPERABILITY
+ * @see IfdId#TYPE_IFD_EXIF
+ */
+ protected int getCurrentIfd() {
+ return mIfdType;
+ }
+
+ /**
+ * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
+ * get the index of this strip.
+ *
+ * @see #getStripCount()
+ */
+ protected int getStripIndex() {
+ return mImageEvent.stripIndex;
+ }
+
+ /**
+ * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
+ * get the number of strip data.
+ *
+ * @see #getStripIndex()
+ */
+ protected int getStripCount() {
+ return mStripCount;
+ }
+
+ /**
+ * When receiving {@link #EVENT_UNCOMPRESSED_STRIP}, call this function to
+ * get the strip size.
+ */
+ protected int getStripSize() {
+ if (mStripSizeTag == null)
+ return 0;
+ return (int) mStripSizeTag.getValueAt(0);
+ }
+
+ /**
+ * When receiving {@link #EVENT_COMPRESSED_IMAGE}, call this function to get
+ * the image data size.
+ */
+ protected int getCompressedImageSize() {
+ if (mJpegSizeTag == null) {
+ return 0;
+ }
+ return (int) mJpegSizeTag.getValueAt(0);
+ }
+
+ private void skipTo(int offset) throws IOException {
+ mTiffStream.skipTo(offset);
+ while (!mCorrespondingEvent.isEmpty() && mCorrespondingEvent.firstKey() < offset) {
+ mCorrespondingEvent.pollFirstEntry();
+ }
+ }
+
+ /**
+ * When getting {@link #EVENT_NEW_TAG} in the tag area of IFD, the tag may
+ * not contain the value if the size of the value is greater than 4 bytes.
+ * When the value is not available here, call this method so that the parser
+ * will emit {@link #EVENT_VALUE_OF_REGISTERED_TAG} when it reaches the area
+ * where the value is located.
+ *
+ * @see #EVENT_VALUE_OF_REGISTERED_TAG
+ */
+ protected void registerForTagValue(ExifTag tag) {
+ if (tag.getOffset() >= mTiffStream.getReadByteCount()) {
+ mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, true));
+ }
+ }
+
+ private void registerIfd(int ifdType, long offset) {
+ // Cast unsigned int to int since the offset is always smaller
+ // than the size of APP1 (65536)
+ mCorrespondingEvent.put((int) offset, new IfdEvent(ifdType, isIfdRequested(ifdType)));
+ }
+
+ private void registerCompressedImage(long offset) {
+ mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_COMPRESSED_IMAGE));
+ }
+
+ private void registerUncompressedStrip(int stripIndex, long offset) {
+ mCorrespondingEvent.put((int) offset, new ImageEvent(EVENT_UNCOMPRESSED_STRIP
+ , stripIndex));
+ }
+
+ private ExifTag readTag() throws IOException, ExifInvalidFormatException {
+ short tagId = mTiffStream.readShort();
+ short dataFormat = mTiffStream.readShort();
+ long numOfComp = mTiffStream.readUnsignedInt();
+ if (numOfComp > Integer.MAX_VALUE) {
+ throw new ExifInvalidFormatException(
+ "Number of component is larger then Integer.MAX_VALUE");
+ }
+ // Some invalid image file contains invalid data type. Ignore those tags
+ if (!ExifTag.isValidType(dataFormat)) {
+ Log.w(TAG, String.format("Tag %04x: Invalid data type %d", tagId, dataFormat));
+ mTiffStream.skip(4);
+ return null;
+ }
+ // TODO: handle numOfComp overflow
+ ExifTag tag = new ExifTag(tagId, dataFormat, (int) numOfComp, mIfdType,
+ ((int) numOfComp) != ExifTag.SIZE_UNDEFINED);
+ int dataSize = tag.getDataSize();
+ if (dataSize > 4) {
+ long offset = mTiffStream.readUnsignedInt();
+ if (offset > Integer.MAX_VALUE) {
+ throw new ExifInvalidFormatException(
+ "offset is larger then Integer.MAX_VALUE");
+ }
+ // Some invalid images put some undefined data before IFD0.
+ // Read the data here.
+ if ((offset < mIfd0Position) && (dataFormat == ExifTag.TYPE_UNDEFINED)) {
+ byte[] buf = new byte[(int) numOfComp];
+ System.arraycopy(mDataAboveIfd0, (int) offset - DEFAULT_IFD0_OFFSET,
+ buf, 0, (int) numOfComp);
+ tag.setValue(buf);
+ } else {
+ tag.setOffset((int) offset);
+ }
+ } else {
+ boolean defCount = tag.hasDefinedCount();
+ // Set defined count to 0 so we can add \0 to non-terminated strings
+ tag.setHasDefinedCount(false);
+ // Read value
+ readFullTagValue(tag);
+ tag.setHasDefinedCount(defCount);
+ mTiffStream.skip(4 - dataSize);
+ // Set the offset to the position of value.
+ tag.setOffset(mTiffStream.getReadByteCount() - 4);
+ }
+ return tag;
+ }
+
+ /**
+ * Check the tag, if the tag is one of the offset tag that points to the IFD
+ * or image the caller is interested in, register the IFD or image.
+ */
+ private void checkOffsetOrImageTag(ExifTag tag) {
+ // Some invalid formattd image contains tag with 0 size.
+ if (tag.getComponentCount() == 0) {
+ return;
+ }
+ short tid = tag.getTagId();
+ int ifd = tag.getIfd();
+ if (tid == TAG_EXIF_IFD && checkAllowed(ifd, ExifInterface.TAG_EXIF_IFD)) {
+ if (isIfdRequested(IfdId.TYPE_IFD_EXIF)
+ || isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
+ registerIfd(IfdId.TYPE_IFD_EXIF, tag.getValueAt(0));
+ }
+ } else if (tid == TAG_GPS_IFD && checkAllowed(ifd, ExifInterface.TAG_GPS_IFD)) {
+ if (isIfdRequested(IfdId.TYPE_IFD_GPS)) {
+ registerIfd(IfdId.TYPE_IFD_GPS, tag.getValueAt(0));
+ }
+ } else if (tid == TAG_INTEROPERABILITY_IFD
+ && checkAllowed(ifd, ExifInterface.TAG_INTEROPERABILITY_IFD)) {
+ if (isIfdRequested(IfdId.TYPE_IFD_INTEROPERABILITY)) {
+ registerIfd(IfdId.TYPE_IFD_INTEROPERABILITY, tag.getValueAt(0));
+ }
+ } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT
+ && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT)) {
+ if (isThumbnailRequested()) {
+ registerCompressedImage(tag.getValueAt(0));
+ }
+ } else if (tid == TAG_JPEG_INTERCHANGE_FORMAT_LENGTH
+ && checkAllowed(ifd, ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH)) {
+ if (isThumbnailRequested()) {
+ mJpegSizeTag = tag;
+ }
+ } else if (tid == TAG_STRIP_OFFSETS && checkAllowed(ifd, ExifInterface.TAG_STRIP_OFFSETS)) {
+ if (isThumbnailRequested()) {
+ if (tag.hasValue()) {
+ for (int i = 0; i < tag.getComponentCount(); i++) {
+ if (tag.getDataType() == ExifTag.TYPE_UNSIGNED_SHORT) {
+ registerUncompressedStrip(i, tag.getValueAt(i));
+ } else {
+ registerUncompressedStrip(i, tag.getValueAt(i));
+ }
+ }
+ } else {
+ mCorrespondingEvent.put(tag.getOffset(), new ExifTagEvent(tag, false));
+ }
+ }
+ } else if (tid == TAG_STRIP_BYTE_COUNTS
+ && checkAllowed(ifd, ExifInterface.TAG_STRIP_BYTE_COUNTS)
+ &&isThumbnailRequested() && tag.hasValue()) {
+ mStripSizeTag = tag;
+ }
+ }
+
+ private boolean checkAllowed(int ifd, int tagId) {
+ int info = mInterface.getTagInfo().get(tagId);
+ if (info == ExifInterface.DEFINITION_NULL) {
+ return false;
+ }
+ return ExifInterface.isIfdAllowed(info, ifd);
+ }
+
+ protected void readFullTagValue(ExifTag tag) throws IOException {
+ // Some invalid images contains tags with wrong size, check it here
+ short type = tag.getDataType();
+ if (type == ExifTag.TYPE_ASCII || type == ExifTag.TYPE_UNDEFINED ||
+ type == ExifTag.TYPE_UNSIGNED_BYTE) {
+ int size = tag.getComponentCount();
+ if (mCorrespondingEvent.size() > 0) {
+ if (mCorrespondingEvent.firstEntry().getKey() < mTiffStream.getReadByteCount()
+ + size) {
+ Object event = mCorrespondingEvent.firstEntry().getValue();
+ if (event instanceof ImageEvent) {
+ // Tag value overlaps thumbnail, ignore thumbnail.
+ Log.w(TAG, "Thumbnail overlaps value for tag: \n" + tag.toString());
+ Entry<Integer, Object> entry = mCorrespondingEvent.pollFirstEntry();
+ Log.w(TAG, "Invalid thumbnail offset: " + entry.getKey());
+ } else {
+ // Tag value overlaps another tag, shorten count
+ if (event instanceof IfdEvent) {
+ Log.w(TAG, "Ifd " + ((IfdEvent) event).ifd
+ + " overlaps value for tag: \n" + tag.toString());
+ } else if (event instanceof ExifTagEvent) {
+ Log.w(TAG, "Tag value for tag: \n"
+ + ((ExifTagEvent) event).tag.toString()
+ + " overlaps value for tag: \n" + tag.toString());
+ }
+ size = mCorrespondingEvent.firstEntry().getKey()
+ - mTiffStream.getReadByteCount();
+ Log.w(TAG, "Invalid size of tag: \n" + tag.toString()
+ + " setting count to: " + size);
+ tag.forceSetComponentCount(size);
+ }
+ }
+ }
+ }
+ switch (tag.getDataType()) {
+ case ExifTag.TYPE_UNSIGNED_BYTE:
+ case ExifTag.TYPE_UNDEFINED: {
+ byte buf[] = new byte[tag.getComponentCount()];
+ read(buf);
+ tag.setValue(buf);
+ }
+ break;
+ case ExifTag.TYPE_ASCII:
+ tag.setValue(readString(tag.getComponentCount()));
+ break;
+ case ExifTag.TYPE_UNSIGNED_LONG: {
+ long value[] = new long[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readUnsignedLong();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_UNSIGNED_RATIONAL: {
+ Rational value[] = new Rational[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readUnsignedRational();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_UNSIGNED_SHORT: {
+ int value[] = new int[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readUnsignedShort();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_LONG: {
+ int value[] = new int[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readLong();
+ }
+ tag.setValue(value);
+ }
+ break;
+ case ExifTag.TYPE_RATIONAL: {
+ Rational value[] = new Rational[tag.getComponentCount()];
+ for (int i = 0, n = value.length; i < n; i++) {
+ value[i] = readRational();
+ }
+ tag.setValue(value);
+ }
+ break;
+ }
+ if (LOGV) {
+ Log.v(TAG, "\n" + tag.toString());
+ }
+ }
+
+ private void parseTiffHeader() throws IOException,
+ ExifInvalidFormatException {
+ short byteOrder = mTiffStream.readShort();
+ if (LITTLE_ENDIAN_TAG == byteOrder) {
+ mTiffStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+ } else if (BIG_ENDIAN_TAG == byteOrder) {
+ mTiffStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+ } else {
+ throw new ExifInvalidFormatException("Invalid TIFF header");
+ }
+
+ if (mTiffStream.readShort() != TIFF_HEADER_TAIL) {
+ throw new ExifInvalidFormatException("Invalid TIFF header");
+ }
+ }
+
+ private boolean seekTiffData(InputStream inputStream) throws IOException,
+ ExifInvalidFormatException {
+ CountedDataInputStream dataStream = new CountedDataInputStream(inputStream);
+ if (dataStream.readShort() != JpegHeader.SOI) {
+ throw new ExifInvalidFormatException("Invalid JPEG format");
+ }
+
+ short marker = dataStream.readShort();
+ while (marker != JpegHeader.EOI
+ && !JpegHeader.isSofMarker(marker)) {
+ int length = dataStream.readUnsignedShort();
+ // Some invalid formatted image contains multiple APP1,
+ // try to find the one with Exif data.
+ if (marker == JpegHeader.APP1) {
+ int header = 0;
+ short headerTail = 0;
+ if (length >= 8) {
+ header = dataStream.readInt();
+ headerTail = dataStream.readShort();
+ length -= 6;
+ if (header == EXIF_HEADER && headerTail == EXIF_HEADER_TAIL) {
+ mTiffStartPosition = dataStream.getReadByteCount();
+ mApp1End = length;
+ mOffsetToApp1EndFromSOF = mTiffStartPosition + mApp1End;
+ return true;
+ }
+ }
+ }
+ if (length < 2 || (length - 2) != dataStream.skip(length - 2)) {
+ Log.w(TAG, "Invalid JPEG format.");
+ return false;
+ }
+ marker = dataStream.readShort();
+ }
+ return false;
+ }
+
+ protected int getOffsetToExifEndFromSOF() {
+ return mOffsetToApp1EndFromSOF;
+ }
+
+ protected int getTiffStartPosition() {
+ return mTiffStartPosition;
+ }
+
+ /**
+ * Reads bytes from the InputStream.
+ */
+ protected int read(byte[] buffer, int offset, int length) throws IOException {
+ return mTiffStream.read(buffer, offset, length);
+ }
+
+ /**
+ * Equivalent to read(buffer, 0, buffer.length).
+ */
+ protected int read(byte[] buffer) throws IOException {
+ return mTiffStream.read(buffer);
+ }
+
+ /**
+ * Reads a String from the InputStream with US-ASCII charset. The parser
+ * will read n bytes and convert it to ascii string. This is used for
+ * reading values of type {@link ExifTag#TYPE_ASCII}.
+ */
+ protected String readString(int n) throws IOException {
+ return readString(n, US_ASCII);
+ }
+
+ /**
+ * Reads a String from the InputStream with the given charset. The parser
+ * will read n bytes and convert it to string. This is used for reading
+ * values of type {@link ExifTag#TYPE_ASCII}.
+ */
+ protected String readString(int n, Charset charset) throws IOException {
+ if (n > 0) {
+ return mTiffStream.readString(n, charset);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_UNSIGNED_SHORT} from the
+ * InputStream.
+ */
+ protected int readUnsignedShort() throws IOException {
+ return mTiffStream.readShort() & 0xffff;
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_UNSIGNED_LONG} from the
+ * InputStream.
+ */
+ protected long readUnsignedLong() throws IOException {
+ return readLong() & 0xffffffffL;
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_UNSIGNED_RATIONAL} from the
+ * InputStream.
+ */
+ protected Rational readUnsignedRational() throws IOException {
+ long nomi = readUnsignedLong();
+ long denomi = readUnsignedLong();
+ return new Rational(nomi, denomi);
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_LONG} from the InputStream.
+ */
+ protected int readLong() throws IOException {
+ return mTiffStream.readInt();
+ }
+
+ /**
+ * Reads value of type {@link ExifTag#TYPE_RATIONAL} from the InputStream.
+ */
+ protected Rational readRational() throws IOException {
+ int nomi = readLong();
+ int denomi = readLong();
+ return new Rational(nomi, denomi);
+ }
+
+ private static class ImageEvent {
+ int stripIndex;
+ int type;
+
+ ImageEvent(int type) {
+ this.stripIndex = 0;
+ this.type = type;
+ }
+
+ ImageEvent(int type, int stripIndex) {
+ this.type = type;
+ this.stripIndex = stripIndex;
+ }
+ }
+
+ private static class IfdEvent {
+ int ifd;
+ boolean isRequested;
+
+ IfdEvent(int ifd, boolean isInterestedIfd) {
+ this.ifd = ifd;
+ this.isRequested = isInterestedIfd;
+ }
+ }
+
+ private static class ExifTagEvent {
+ ExifTag tag;
+ boolean isRequested;
+
+ ExifTagEvent(ExifTag tag, boolean isRequireByUser) {
+ this.tag = tag;
+ this.isRequested = isRequireByUser;
+ }
+ }
+
+ /**
+ * Gets the byte order of the current InputStream.
+ */
+ protected ByteOrder getByteOrder() {
+ return mTiffStream.getByteOrder();
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifReader.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifReader.java
new file mode 100644
index 0000000..68e972f
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifReader.java
@@ -0,0 +1,92 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class reads the EXIF header of a JPEG file and stores it in
+ * {@link ExifData}.
+ */
+class ExifReader {
+ private static final String TAG = "ExifReader";
+
+ private final ExifInterface mInterface;
+
+ ExifReader(ExifInterface iRef) {
+ mInterface = iRef;
+ }
+
+ /**
+ * Parses the inputStream and and returns the EXIF data in an
+ * {@link ExifData}.
+ *
+ * @throws ExifInvalidFormatException
+ * @throws IOException
+ */
+ protected ExifData read(InputStream inputStream) throws ExifInvalidFormatException,
+ IOException {
+ ExifParser parser = ExifParser.parse(inputStream, mInterface);
+ ExifData exifData = new ExifData(parser.getByteOrder());
+ ExifTag tag = null;
+
+ int event = parser.next();
+ while (event != ExifParser.EVENT_END) {
+ switch (event) {
+ case ExifParser.EVENT_START_OF_IFD:
+ exifData.addIfdData(new IfdData(parser.getCurrentIfd()));
+ break;
+ case ExifParser.EVENT_NEW_TAG:
+ tag = parser.getTag();
+ if (!tag.hasValue()) {
+ parser.registerForTagValue(tag);
+ } else {
+ exifData.getIfdData(tag.getIfd()).setTag(tag);
+ }
+ break;
+ case ExifParser.EVENT_VALUE_OF_REGISTERED_TAG:
+ tag = parser.getTag();
+ if (tag.getDataType() == ExifTag.TYPE_UNDEFINED) {
+ parser.readFullTagValue(tag);
+ }
+ exifData.getIfdData(tag.getIfd()).setTag(tag);
+ break;
+ case ExifParser.EVENT_COMPRESSED_IMAGE:
+ byte buf[] = new byte[parser.getCompressedImageSize()];
+ if (buf.length == parser.read(buf)) {
+ exifData.setCompressedThumbnail(buf);
+ } else {
+ Log.w(TAG, "Failed to read the compressed thumbnail");
+ }
+ break;
+ case ExifParser.EVENT_UNCOMPRESSED_STRIP:
+ buf = new byte[parser.getStripSize()];
+ if (buf.length == parser.read(buf)) {
+ exifData.setStripBytes(parser.getStripIndex(), buf);
+ } else {
+ Log.w(TAG, "Failed to read the strip bytes");
+ }
+ break;
+ }
+ event = parser.next();
+ }
+ return exifData;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifTag.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifTag.java
new file mode 100644
index 0000000..b8b3872
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/ExifTag.java
@@ -0,0 +1,1008 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * This class stores information of an EXIF tag. For more information about
+ * defined EXIF tags, please read the Jeita EXIF 2.2 standard. Tags should be
+ * instantiated using {@link ExifInterface#buildTag}.
+ *
+ * @see ExifInterface
+ */
+public class ExifTag {
+ /**
+ * The BYTE type in the EXIF standard. An 8-bit unsigned integer.
+ */
+ public static final short TYPE_UNSIGNED_BYTE = 1;
+ /**
+ * The ASCII type in the EXIF standard. An 8-bit byte containing one 7-bit
+ * ASCII code. The final byte is terminated with NULL.
+ */
+ public static final short TYPE_ASCII = 2;
+ /**
+ * The SHORT type in the EXIF standard. A 16-bit (2-byte) unsigned integer
+ */
+ public static final short TYPE_UNSIGNED_SHORT = 3;
+ /**
+ * The LONG type in the EXIF standard. A 32-bit (4-byte) unsigned integer
+ */
+ public static final short TYPE_UNSIGNED_LONG = 4;
+ /**
+ * The RATIONAL type of EXIF standard. It consists of two LONGs. The first
+ * one is the numerator and the second one expresses the denominator.
+ */
+ public static final short TYPE_UNSIGNED_RATIONAL = 5;
+ /**
+ * The UNDEFINED type in the EXIF standard. An 8-bit byte that can take any
+ * value depending on the field definition.
+ */
+ public static final short TYPE_UNDEFINED = 7;
+ /**
+ * The SLONG type in the EXIF standard. A 32-bit (4-byte) signed integer
+ * (2's complement notation).
+ */
+ public static final short TYPE_LONG = 9;
+ /**
+ * The SRATIONAL type of EXIF standard. It consists of two SLONGs. The first
+ * one is the numerator and the second one is the denominator.
+ */
+ public static final short TYPE_RATIONAL = 10;
+
+ private static Charset US_ASCII = Charset.forName("US-ASCII");
+ private static final int TYPE_TO_SIZE_MAP[] = new int[11];
+ private static final int UNSIGNED_SHORT_MAX = 65535;
+ private static final long UNSIGNED_LONG_MAX = 4294967295L;
+ private static final long LONG_MAX = Integer.MAX_VALUE;
+ private static final long LONG_MIN = Integer.MIN_VALUE;
+
+ static {
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_BYTE] = 1;
+ TYPE_TO_SIZE_MAP[TYPE_ASCII] = 1;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_SHORT] = 2;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_LONG] = 4;
+ TYPE_TO_SIZE_MAP[TYPE_UNSIGNED_RATIONAL] = 8;
+ TYPE_TO_SIZE_MAP[TYPE_UNDEFINED] = 1;
+ TYPE_TO_SIZE_MAP[TYPE_LONG] = 4;
+ TYPE_TO_SIZE_MAP[TYPE_RATIONAL] = 8;
+ }
+
+ static final int SIZE_UNDEFINED = 0;
+
+ // Exif TagId
+ private final short mTagId;
+ // Exif Tag Type
+ private final short mDataType;
+ // If tag has defined count
+ private boolean mHasDefinedDefaultComponentCount;
+ // Actual data count in tag (should be number of elements in value array)
+ private int mComponentCountActual;
+ // The ifd that this tag should be put in
+ private int mIfd;
+ // The value (array of elements of type Tag Type)
+ private Object mValue;
+ // Value offset in exif header.
+ private int mOffset;
+
+ private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("yyyy:MM:dd kk:mm:ss");
+
+ /**
+ * Returns true if the given IFD is a valid IFD.
+ */
+ public static boolean isValidIfd(int ifdId) {
+ return ifdId == IfdId.TYPE_IFD_0 || ifdId == IfdId.TYPE_IFD_1
+ || ifdId == IfdId.TYPE_IFD_EXIF || ifdId == IfdId.TYPE_IFD_INTEROPERABILITY
+ || ifdId == IfdId.TYPE_IFD_GPS;
+ }
+
+ /**
+ * Returns true if a given type is a valid tag type.
+ */
+ public static boolean isValidType(short type) {
+ return type == TYPE_UNSIGNED_BYTE || type == TYPE_ASCII ||
+ type == TYPE_UNSIGNED_SHORT || type == TYPE_UNSIGNED_LONG ||
+ type == TYPE_UNSIGNED_RATIONAL || type == TYPE_UNDEFINED ||
+ type == TYPE_LONG || type == TYPE_RATIONAL;
+ }
+
+ // Use builtTag in ExifInterface instead of constructor.
+ ExifTag(short tagId, short type, int componentCount, int ifd,
+ boolean hasDefinedComponentCount) {
+ mTagId = tagId;
+ mDataType = type;
+ mComponentCountActual = componentCount;
+ mHasDefinedDefaultComponentCount = hasDefinedComponentCount;
+ mIfd = ifd;
+ mValue = null;
+ }
+
+ /**
+ * Gets the element size of the given data type in bytes.
+ *
+ * @see #TYPE_ASCII
+ * @see #TYPE_LONG
+ * @see #TYPE_RATIONAL
+ * @see #TYPE_UNDEFINED
+ * @see #TYPE_UNSIGNED_BYTE
+ * @see #TYPE_UNSIGNED_LONG
+ * @see #TYPE_UNSIGNED_RATIONAL
+ * @see #TYPE_UNSIGNED_SHORT
+ */
+ public static int getElementSize(short type) {
+ return TYPE_TO_SIZE_MAP[type];
+ }
+
+ /**
+ * Returns the ID of the IFD this tag belongs to.
+ *
+ * @see IfdId#TYPE_IFD_0
+ * @see IfdId#TYPE_IFD_1
+ * @see IfdId#TYPE_IFD_EXIF
+ * @see IfdId#TYPE_IFD_GPS
+ * @see IfdId#TYPE_IFD_INTEROPERABILITY
+ */
+ public int getIfd() {
+ return mIfd;
+ }
+
+ protected void setIfd(int ifdId) {
+ mIfd = ifdId;
+ }
+
+ /**
+ * Gets the TID of this tag.
+ */
+ public short getTagId() {
+ return mTagId;
+ }
+
+ /**
+ * Gets the data type of this tag
+ *
+ * @see #TYPE_ASCII
+ * @see #TYPE_LONG
+ * @see #TYPE_RATIONAL
+ * @see #TYPE_UNDEFINED
+ * @see #TYPE_UNSIGNED_BYTE
+ * @see #TYPE_UNSIGNED_LONG
+ * @see #TYPE_UNSIGNED_RATIONAL
+ * @see #TYPE_UNSIGNED_SHORT
+ */
+ public short getDataType() {
+ return mDataType;
+ }
+
+ /**
+ * Gets the total data size in bytes of the value of this tag.
+ */
+ public int getDataSize() {
+ return getComponentCount() * getElementSize(getDataType());
+ }
+
+ /**
+ * Gets the component count of this tag.
+ */
+
+ // TODO: fix integer overflows with this
+ public int getComponentCount() {
+ return mComponentCountActual;
+ }
+
+ /**
+ * Sets the component count of this tag. Call this function before
+ * setValue() if the length of value does not match the component count.
+ */
+ protected void forceSetComponentCount(int count) {
+ mComponentCountActual = count;
+ }
+
+ /**
+ * Returns true if this ExifTag contains value; otherwise, this tag will
+ * contain an offset value that is determined when the tag is written.
+ */
+ public boolean hasValue() {
+ return mValue != null;
+ }
+
+ /**
+ * Sets integer values into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_SHORT}. This method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The value.length does NOT match the component count in the definition
+ * for this tag.</li>
+ * </ul>
+ */
+ public boolean setValue(int[] value) {
+ if (checkBadComponentCount(value.length)) {
+ return false;
+ }
+ if (mDataType != TYPE_UNSIGNED_SHORT && mDataType != TYPE_LONG &&
+ mDataType != TYPE_UNSIGNED_LONG) {
+ return false;
+ }
+ if (mDataType == TYPE_UNSIGNED_SHORT && checkOverflowForUnsignedShort(value)) {
+ return false;
+ } else if (mDataType == TYPE_UNSIGNED_LONG && checkOverflowForUnsignedLong(value)) {
+ return false;
+ }
+
+ long[] data = new long[value.length];
+ for (int i = 0; i < value.length; i++) {
+ data[i] = value[i];
+ }
+ mValue = data;
+ mComponentCountActual = value.length;
+ return true;
+ }
+
+ /**
+ * Sets integer value into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_SHORT}, or {@link #TYPE_LONG}. This method
+ * will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_SHORT},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The component count in the definition of this tag is not 1.</li>
+ * </ul>
+ */
+ public boolean setValue(int value) {
+ return setValue(new int[] {
+ value
+ });
+ }
+
+ /**
+ * Sets long values into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_LONG}. This method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The value.length does NOT match the component count in the definition
+ * for this tag.</li>
+ * </ul>
+ */
+ public boolean setValue(long[] value) {
+ if (checkBadComponentCount(value.length) || mDataType != TYPE_UNSIGNED_LONG) {
+ return false;
+ }
+ if (checkOverflowForUnsignedLong(value)) {
+ return false;
+ }
+ mValue = value;
+ mComponentCountActual = value.length;
+ return true;
+ }
+
+ /**
+ * Sets long values into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_LONG}. This method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_LONG}.</li>
+ * <li>The value overflows.</li>
+ * <li>The component count in the definition for this tag is not 1.</li>
+ * </ul>
+ */
+ public boolean setValue(long value) {
+ return setValue(new long[] {
+ value
+ });
+ }
+
+ /**
+ * Sets a string value into this tag. This method should be used for tags of
+ * type {@link #TYPE_ASCII}. The string is converted to an ASCII string.
+ * Characters that cannot be converted are replaced with '?'. The length of
+ * the string must be equal to either (component count -1) or (component
+ * count). The final byte will be set to the string null terminator '\0',
+ * overwriting the last character in the string if the value.length is equal
+ * to the component count. This method will fail if:
+ * <ul>
+ * <li>The data type is not {@link #TYPE_ASCII} or {@link #TYPE_UNDEFINED}.</li>
+ * <li>The length of the string is not equal to (component count -1) or
+ * (component count) in the definition for this tag.</li>
+ * </ul>
+ */
+ public boolean setValue(String value) {
+ if (mDataType != TYPE_ASCII && mDataType != TYPE_UNDEFINED) {
+ return false;
+ }
+
+ byte[] buf = value.getBytes(US_ASCII);
+ byte[] finalBuf = buf;
+ if (buf.length > 0) {
+ finalBuf = (buf[buf.length - 1] == 0 || mDataType == TYPE_UNDEFINED) ? buf : Arrays
+ .copyOf(buf, buf.length + 1);
+ } else if (mDataType == TYPE_ASCII && mComponentCountActual == 1) {
+ finalBuf = new byte[] { 0 };
+ }
+ int count = finalBuf.length;
+ if (checkBadComponentCount(count)) {
+ return false;
+ }
+ mComponentCountActual = count;
+ mValue = finalBuf;
+ return true;
+ }
+
+ /**
+ * Sets Rational values into this tag. This method should be used for tags
+ * of type {@link #TYPE_UNSIGNED_RATIONAL}, or {@link #TYPE_RATIONAL}. This
+ * method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL}
+ * or {@link #TYPE_RATIONAL}.</li>
+ * <li>The value overflows.</li>
+ * <li>The value.length does NOT match the component count in the definition
+ * for this tag.</li>
+ * </ul>
+ *
+ * @see Rational
+ */
+ public boolean setValue(Rational[] value) {
+ if (checkBadComponentCount(value.length)) {
+ return false;
+ }
+ if (mDataType != TYPE_UNSIGNED_RATIONAL && mDataType != TYPE_RATIONAL) {
+ return false;
+ }
+ if (mDataType == TYPE_UNSIGNED_RATIONAL && checkOverflowForUnsignedRational(value)) {
+ return false;
+ } else if (mDataType == TYPE_RATIONAL && checkOverflowForRational(value)) {
+ return false;
+ }
+
+ mValue = value;
+ mComponentCountActual = value.length;
+ return true;
+ }
+
+ /**
+ * Sets a Rational value into this tag. This method should be used for tags
+ * of type {@link #TYPE_UNSIGNED_RATIONAL}, or {@link #TYPE_RATIONAL}. This
+ * method will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_RATIONAL}
+ * or {@link #TYPE_RATIONAL}.</li>
+ * <li>The value overflows.</li>
+ * <li>The component count in the definition for this tag is not 1.</li>
+ * </ul>
+ *
+ * @see Rational
+ */
+ public boolean setValue(Rational value) {
+ return setValue(new Rational[] {
+ value
+ });
+ }
+
+ /**
+ * Sets byte values into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_BYTE} or {@link #TYPE_UNDEFINED}. This method
+ * will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
+ * {@link #TYPE_UNDEFINED} .</li>
+ * <li>The length does NOT match the component count in the definition for
+ * this tag.</li>
+ * </ul>
+ */
+ public boolean setValue(byte[] value, int offset, int length) {
+ if (checkBadComponentCount(length)) {
+ return false;
+ }
+ if (mDataType != TYPE_UNSIGNED_BYTE && mDataType != TYPE_UNDEFINED) {
+ return false;
+ }
+ mValue = new byte[length];
+ System.arraycopy(value, offset, mValue, 0, length);
+ mComponentCountActual = length;
+ return true;
+ }
+
+ /**
+ * Equivalent to setValue(value, 0, value.length).
+ */
+ public boolean setValue(byte[] value) {
+ return setValue(value, 0, value.length);
+ }
+
+ /**
+ * Sets byte value into this tag. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_BYTE} or {@link #TYPE_UNDEFINED}. This method
+ * will fail if:
+ * <ul>
+ * <li>The component type of this tag is not {@link #TYPE_UNSIGNED_BYTE} or
+ * {@link #TYPE_UNDEFINED} .</li>
+ * <li>The component count in the definition for this tag is not 1.</li>
+ * </ul>
+ */
+ public boolean setValue(byte value) {
+ return setValue(new byte[] {
+ value
+ });
+ }
+
+ /**
+ * Sets the value for this tag using an appropriate setValue method for the
+ * given object. This method will fail if:
+ * <ul>
+ * <li>The corresponding setValue method for the class of the object passed
+ * in would fail.</li>
+ * <li>There is no obvious way to cast the object passed in into an EXIF tag
+ * type.</li>
+ * </ul>
+ */
+ public boolean setValue(Object obj) {
+ if (obj == null) {
+ return false;
+ } else if (obj instanceof Short) {
+ return setValue(((Short) obj).shortValue() & 0x0ffff);
+ } else if (obj instanceof String) {
+ return setValue((String) obj);
+ } else if (obj instanceof int[]) {
+ return setValue((int[]) obj);
+ } else if (obj instanceof long[]) {
+ return setValue((long[]) obj);
+ } else if (obj instanceof Rational) {
+ return setValue((Rational) obj);
+ } else if (obj instanceof Rational[]) {
+ return setValue((Rational[]) obj);
+ } else if (obj instanceof byte[]) {
+ return setValue((byte[]) obj);
+ } else if (obj instanceof Integer) {
+ return setValue(((Integer) obj).intValue());
+ } else if (obj instanceof Long) {
+ return setValue(((Long) obj).longValue());
+ } else if (obj instanceof Byte) {
+ return setValue(((Byte) obj).byteValue());
+ } else if (obj instanceof Short[]) {
+ // Nulls in this array are treated as zeroes.
+ Short[] arr = (Short[]) obj;
+ int[] fin = new int[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ fin[i] = (arr[i] == null) ? 0 : arr[i].shortValue() & 0x0ffff;
+ }
+ return setValue(fin);
+ } else if (obj instanceof Integer[]) {
+ // Nulls in this array are treated as zeroes.
+ Integer[] arr = (Integer[]) obj;
+ int[] fin = new int[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ fin[i] = (arr[i] == null) ? 0 : arr[i].intValue();
+ }
+ return setValue(fin);
+ } else if (obj instanceof Long[]) {
+ // Nulls in this array are treated as zeroes.
+ Long[] arr = (Long[]) obj;
+ long[] fin = new long[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ fin[i] = (arr[i] == null) ? 0 : arr[i].longValue();
+ }
+ return setValue(fin);
+ } else if (obj instanceof Byte[]) {
+ // Nulls in this array are treated as zeroes.
+ Byte[] arr = (Byte[]) obj;
+ byte[] fin = new byte[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ fin[i] = (arr[i] == null) ? 0 : arr[i].byteValue();
+ }
+ return setValue(fin);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Sets a timestamp to this tag. The method converts the timestamp with the
+ * format of "yyyy:MM:dd kk:mm:ss" and calls {@link #setValue(String)}. This
+ * method will fail if the data type is not {@link #TYPE_ASCII} or the
+ * component count of this tag is not 20 or undefined.
+ *
+ * @param time the number of milliseconds since Jan. 1, 1970 GMT
+ * @return true on success
+ */
+ public boolean setTimeValue(long time) {
+ // synchronized on TIME_FORMAT as SimpleDateFormat is not thread safe
+ synchronized (TIME_FORMAT) {
+ return setValue(TIME_FORMAT.format(new Date(time)));
+ }
+ }
+
+ /**
+ * Gets the value as a String. This method should be used for tags of type
+ * {@link #TYPE_ASCII}.
+ *
+ * @return the value as a String, or null if the tag's value does not exist
+ * or cannot be converted to a String.
+ */
+ public String getValueAsString() {
+ if (mValue == null) {
+ return null;
+ } else if (mValue instanceof String) {
+ return (String) mValue;
+ } else if (mValue instanceof byte[]) {
+ return new String((byte[]) mValue, US_ASCII);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value as a String. This method should be used for tags of type
+ * {@link #TYPE_ASCII}.
+ *
+ * @param defaultValue the String to return if the tag's value does not
+ * exist or cannot be converted to a String.
+ * @return the tag's value as a String, or the defaultValue.
+ */
+ public String getValueAsString(String defaultValue) {
+ String s = getValueAsString();
+ if (s == null) {
+ return defaultValue;
+ }
+ return s;
+ }
+
+ /**
+ * Gets the value as a byte array. This method should be used for tags of
+ * type {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
+ *
+ * @return the value as a byte array, or null if the tag's value does not
+ * exist or cannot be converted to a byte array.
+ */
+ public byte[] getValueAsBytes() {
+ if (mValue instanceof byte[]) {
+ return (byte[]) mValue;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value as a byte. If there are more than 1 bytes in this value,
+ * gets the first byte. This method should be used for tags of type
+ * {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
+ *
+ * @param defaultValue the byte to return if tag's value does not exist or
+ * cannot be converted to a byte.
+ * @return the tag's value as a byte, or the defaultValue.
+ */
+ public byte getValueAsByte(byte defaultValue) {
+ byte[] b = getValueAsBytes();
+ if (b == null || b.length < 1) {
+ return defaultValue;
+ }
+ return b[0];
+ }
+
+ /**
+ * Gets the value as an array of Rationals. This method should be used for
+ * tags of type {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ *
+ * @return the value as as an array of Rationals, or null if the tag's value
+ * does not exist or cannot be converted to an array of Rationals.
+ */
+ public Rational[] getValueAsRationals() {
+ if (mValue instanceof Rational[]) {
+ return (Rational[]) mValue;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value as a Rational. If there are more than 1 Rationals in this
+ * value, gets the first one. This method should be used for tags of type
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ *
+ * @param defaultValue the Rational to return if tag's value does not exist
+ * or cannot be converted to a Rational.
+ * @return the tag's value as a Rational, or the defaultValue.
+ */
+ public Rational getValueAsRational(Rational defaultValue) {
+ Rational[] r = getValueAsRationals();
+ if (r == null || r.length < 1) {
+ return defaultValue;
+ }
+ return r[0];
+ }
+
+ /**
+ * Gets the value as a Rational. If there are more than 1 Rationals in this
+ * value, gets the first one. This method should be used for tags of type
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ *
+ * @param defaultValue the numerator of the Rational to return if tag's
+ * value does not exist or cannot be converted to a Rational (the
+ * denominator will be 1).
+ * @return the tag's value as a Rational, or the defaultValue.
+ */
+ public Rational getValueAsRational(long defaultValue) {
+ Rational defaultVal = new Rational(defaultValue, 1);
+ return getValueAsRational(defaultVal);
+ }
+
+ /**
+ * Gets the value as an array of ints. This method should be used for tags
+ * of type {@link #TYPE_UNSIGNED_SHORT}, {@link #TYPE_UNSIGNED_LONG}.
+ *
+ * @return the value as as an array of ints, or null if the tag's value does
+ * not exist or cannot be converted to an array of ints.
+ */
+ public int[] getValueAsInts() {
+ if (mValue == null) {
+ return null;
+ } else if (mValue instanceof long[]) {
+ long[] val = (long[]) mValue;
+ int[] arr = new int[val.length];
+ for (int i = 0; i < val.length; i++) {
+ arr[i] = (int) val[i]; // Truncates
+ }
+ return arr;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value as an int. If there are more than 1 ints in this value,
+ * gets the first one. This method should be used for tags of type
+ * {@link #TYPE_UNSIGNED_SHORT}, {@link #TYPE_UNSIGNED_LONG}.
+ *
+ * @param defaultValue the int to return if tag's value does not exist or
+ * cannot be converted to an int.
+ * @return the tag's value as a int, or the defaultValue.
+ */
+ public int getValueAsInt(int defaultValue) {
+ int[] i = getValueAsInts();
+ if (i == null || i.length < 1) {
+ return defaultValue;
+ }
+ return i[0];
+ }
+
+ /**
+ * Gets the value as an array of longs. This method should be used for tags
+ * of type {@link #TYPE_UNSIGNED_LONG}.
+ *
+ * @return the value as as an array of longs, or null if the tag's value
+ * does not exist or cannot be converted to an array of longs.
+ */
+ public long[] getValueAsLongs() {
+ if (mValue instanceof long[]) {
+ return (long[]) mValue;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value or null if none exists. If there are more than 1 longs in
+ * this value, gets the first one. This method should be used for tags of
+ * type {@link #TYPE_UNSIGNED_LONG}.
+ *
+ * @param defaultValue the long to return if tag's value does not exist or
+ * cannot be converted to a long.
+ * @return the tag's value as a long, or the defaultValue.
+ */
+ public long getValueAsLong(long defaultValue) {
+ long[] l = getValueAsLongs();
+ if (l == null || l.length < 1) {
+ return defaultValue;
+ }
+ return l[0];
+ }
+
+ /**
+ * Gets the tag's value or null if none exists.
+ */
+ public Object getValue() {
+ return mValue;
+ }
+
+ /**
+ * Gets a long representation of the value.
+ *
+ * @param defaultValue value to return if there is no value or value is a
+ * rational with a denominator of 0.
+ * @return the tag's value as a long, or defaultValue if no representation
+ * exists.
+ */
+ public long forceGetValueAsLong(long defaultValue) {
+ long[] l = getValueAsLongs();
+ if (l != null && l.length >= 1) {
+ return l[0];
+ }
+ byte[] b = getValueAsBytes();
+ if (b != null && b.length >= 1) {
+ return b[0];
+ }
+ Rational[] r = getValueAsRationals();
+ if (r != null && r.length >= 1 && r[0].getDenominator() != 0) {
+ return (long) r[0].toDouble();
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Gets a string representation of the value.
+ */
+ public String forceGetValueAsString() {
+ if (mValue == null) {
+ return "";
+ } else if (mValue instanceof byte[]) {
+ if (mDataType == TYPE_ASCII) {
+ return new String((byte[]) mValue, US_ASCII);
+ } else {
+ return Arrays.toString((byte[]) mValue);
+ }
+ } else if (mValue instanceof long[]) {
+ if (((long[]) mValue).length == 1) {
+ return String.valueOf(((long[]) mValue)[0]);
+ } else {
+ return Arrays.toString((long[]) mValue);
+ }
+ } else if (mValue instanceof Object[]) {
+ if (((Object[]) mValue).length == 1) {
+ Object val = ((Object[]) mValue)[0];
+ if (val == null) {
+ return "";
+ } else {
+ return val.toString();
+ }
+ } else {
+ return Arrays.toString((Object[]) mValue);
+ }
+ } else {
+ return mValue.toString();
+ }
+ }
+
+ /**
+ * Gets the value for type {@link #TYPE_ASCII}, {@link #TYPE_LONG},
+ * {@link #TYPE_UNDEFINED}, {@link #TYPE_UNSIGNED_BYTE},
+ * {@link #TYPE_UNSIGNED_LONG}, or {@link #TYPE_UNSIGNED_SHORT}. For
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}, call
+ * {@link #getRational(int)} instead.
+ *
+ * @exception IllegalArgumentException if the data type is
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ */
+ protected long getValueAt(int index) {
+ if (mValue instanceof long[]) {
+ return ((long[]) mValue)[index];
+ } else if (mValue instanceof byte[]) {
+ return ((byte[]) mValue)[index];
+ }
+ throw new IllegalArgumentException("Cannot get integer value from "
+ + convertTypeToString(mDataType));
+ }
+
+ /**
+ * Gets the {@link #TYPE_ASCII} data.
+ *
+ * @exception IllegalArgumentException If the type is NOT
+ * {@link #TYPE_ASCII}.
+ */
+ protected String getString() {
+ if (mDataType != TYPE_ASCII) {
+ throw new IllegalArgumentException("Cannot get ASCII value from "
+ + convertTypeToString(mDataType));
+ }
+ return new String((byte[]) mValue, US_ASCII);
+ }
+
+ /*
+ * Get the converted ascii byte. Used by ExifOutputStream.
+ */
+ protected byte[] getStringByte() {
+ return (byte[]) mValue;
+ }
+
+ /**
+ * Gets the {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL} data.
+ *
+ * @exception IllegalArgumentException If the type is NOT
+ * {@link #TYPE_RATIONAL} or {@link #TYPE_UNSIGNED_RATIONAL}.
+ */
+ protected Rational getRational(int index) {
+ if ((mDataType != TYPE_RATIONAL) && (mDataType != TYPE_UNSIGNED_RATIONAL)) {
+ throw new IllegalArgumentException("Cannot get RATIONAL value from "
+ + convertTypeToString(mDataType));
+ }
+ return ((Rational[]) mValue)[index];
+ }
+
+ /**
+ * Equivalent to getBytes(buffer, 0, buffer.length).
+ */
+ protected void getBytes(byte[] buf) {
+ getBytes(buf, 0, buf.length);
+ }
+
+ /**
+ * Gets the {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE} data.
+ *
+ * @param buf the byte array in which to store the bytes read.
+ * @param offset the initial position in buffer to store the bytes.
+ * @param length the maximum number of bytes to store in buffer. If length >
+ * component count, only the valid bytes will be stored.
+ * @exception IllegalArgumentException If the type is NOT
+ * {@link #TYPE_UNDEFINED} or {@link #TYPE_UNSIGNED_BYTE}.
+ */
+ protected void getBytes(byte[] buf, int offset, int length) {
+ if ((mDataType != TYPE_UNDEFINED) && (mDataType != TYPE_UNSIGNED_BYTE)) {
+ throw new IllegalArgumentException("Cannot get BYTE value from "
+ + convertTypeToString(mDataType));
+ }
+ System.arraycopy(mValue, 0, buf, offset,
+ (length > mComponentCountActual) ? mComponentCountActual : length);
+ }
+
+ /**
+ * Gets the offset of this tag. This is only valid if this data size > 4 and
+ * contains an offset to the location of the actual value.
+ */
+ protected int getOffset() {
+ return mOffset;
+ }
+
+ /**
+ * Sets the offset of this tag.
+ */
+ protected void setOffset(int offset) {
+ mOffset = offset;
+ }
+
+ protected void setHasDefinedCount(boolean d) {
+ mHasDefinedDefaultComponentCount = d;
+ }
+
+ protected boolean hasDefinedCount() {
+ return mHasDefinedDefaultComponentCount;
+ }
+
+ private boolean checkBadComponentCount(int count) {
+ if (mHasDefinedDefaultComponentCount && (mComponentCountActual != count)) {
+ return true;
+ }
+ return false;
+ }
+
+ private static String convertTypeToString(short type) {
+ switch (type) {
+ case TYPE_UNSIGNED_BYTE:
+ return "UNSIGNED_BYTE";
+ case TYPE_ASCII:
+ return "ASCII";
+ case TYPE_UNSIGNED_SHORT:
+ return "UNSIGNED_SHORT";
+ case TYPE_UNSIGNED_LONG:
+ return "UNSIGNED_LONG";
+ case TYPE_UNSIGNED_RATIONAL:
+ return "UNSIGNED_RATIONAL";
+ case TYPE_UNDEFINED:
+ return "UNDEFINED";
+ case TYPE_LONG:
+ return "LONG";
+ case TYPE_RATIONAL:
+ return "RATIONAL";
+ default:
+ return "";
+ }
+ }
+
+ private boolean checkOverflowForUnsignedShort(int[] value) {
+ for (int v : value) {
+ if (v > UNSIGNED_SHORT_MAX || v < 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkOverflowForUnsignedLong(long[] value) {
+ for (long v : value) {
+ if (v < 0 || v > UNSIGNED_LONG_MAX) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkOverflowForUnsignedLong(int[] value) {
+ for (int v : value) {
+ if (v < 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkOverflowForUnsignedRational(Rational[] value) {
+ for (Rational v : value) {
+ if (v.getNumerator() < 0 || v.getDenominator() < 0
+ || v.getNumerator() > UNSIGNED_LONG_MAX
+ || v.getDenominator() > UNSIGNED_LONG_MAX) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean checkOverflowForRational(Rational[] value) {
+ for (Rational v : value) {
+ if (v.getNumerator() < LONG_MIN || v.getDenominator() < LONG_MIN
+ || v.getNumerator() > LONG_MAX
+ || v.getDenominator() > LONG_MAX) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof ExifTag) {
+ ExifTag tag = (ExifTag) obj;
+ if (tag.mTagId != this.mTagId
+ || tag.mComponentCountActual != this.mComponentCountActual
+ || tag.mDataType != this.mDataType) {
+ return false;
+ }
+ if (mValue != null) {
+ if (tag.mValue == null) {
+ return false;
+ } else if (mValue instanceof long[]) {
+ if (!(tag.mValue instanceof long[])) {
+ return false;
+ }
+ return Arrays.equals((long[]) mValue, (long[]) tag.mValue);
+ } else if (mValue instanceof Rational[]) {
+ if (!(tag.mValue instanceof Rational[])) {
+ return false;
+ }
+ return Arrays.equals((Rational[]) mValue, (Rational[]) tag.mValue);
+ } else if (mValue instanceof byte[]) {
+ if (!(tag.mValue instanceof byte[])) {
+ return false;
+ }
+ return Arrays.equals((byte[]) mValue, (byte[]) tag.mValue);
+ } else {
+ return mValue.equals(tag.mValue);
+ }
+ } else {
+ return tag.mValue == null;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("tag id: %04X\n", mTagId) + "ifd id: " + mIfd + "\ntype: "
+ + convertTypeToString(mDataType) + "\ncount: " + mComponentCountActual
+ + "\noffset: " + mOffset + "\nvalue: " + forceGetValueAsString() + "\n";
+ }
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdData.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdData.java
new file mode 100644
index 0000000..093944a
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdData.java
@@ -0,0 +1,152 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class stores all the tags in an IFD.
+ *
+ * @see ExifData
+ * @see ExifTag
+ */
+class IfdData {
+
+ private final int mIfdId;
+ private final Map<Short, ExifTag> mExifTags = new HashMap<Short, ExifTag>();
+ private int mOffsetToNextIfd = 0;
+ private static final int[] sIfds = {
+ IfdId.TYPE_IFD_0, IfdId.TYPE_IFD_1, IfdId.TYPE_IFD_EXIF,
+ IfdId.TYPE_IFD_INTEROPERABILITY, IfdId.TYPE_IFD_GPS
+ };
+ /**
+ * Creates an IfdData with given IFD ID.
+ *
+ * @see IfdId#TYPE_IFD_0
+ * @see IfdId#TYPE_IFD_1
+ * @see IfdId#TYPE_IFD_EXIF
+ * @see IfdId#TYPE_IFD_GPS
+ * @see IfdId#TYPE_IFD_INTEROPERABILITY
+ */
+ IfdData(int ifdId) {
+ mIfdId = ifdId;
+ }
+
+ static protected int[] getIfds() {
+ return sIfds;
+ }
+
+ /**
+ * Get a array the contains all {@link ExifTag} in this IFD.
+ */
+ protected ExifTag[] getAllTags() {
+ return mExifTags.values().toArray(new ExifTag[mExifTags.size()]);
+ }
+
+ /**
+ * Gets the ID of this IFD.
+ *
+ * @see IfdId#TYPE_IFD_0
+ * @see IfdId#TYPE_IFD_1
+ * @see IfdId#TYPE_IFD_EXIF
+ * @see IfdId#TYPE_IFD_GPS
+ * @see IfdId#TYPE_IFD_INTEROPERABILITY
+ */
+ protected int getId() {
+ return mIfdId;
+ }
+
+ /**
+ * Gets the {@link ExifTag} with given tag id. Return null if there is no
+ * such tag.
+ */
+ protected ExifTag getTag(short tagId) {
+ return mExifTags.get(tagId);
+ }
+
+ /**
+ * Adds or replaces a {@link ExifTag}.
+ */
+ protected ExifTag setTag(ExifTag tag) {
+ tag.setIfd(mIfdId);
+ return mExifTags.put(tag.getTagId(), tag);
+ }
+
+ protected boolean checkCollision(short tagId) {
+ return mExifTags.get(tagId) != null;
+ }
+
+ /**
+ * Removes the tag of the given ID
+ */
+ protected void removeTag(short tagId) {
+ mExifTags.remove(tagId);
+ }
+
+ /**
+ * Gets the tags count in the IFD.
+ */
+ protected int getTagCount() {
+ return mExifTags.size();
+ }
+
+ /**
+ * Sets the offset of next IFD.
+ */
+ protected void setOffsetToNextIfd(int offset) {
+ mOffsetToNextIfd = offset;
+ }
+
+ /**
+ * Gets the offset of next IFD.
+ */
+ protected int getOffsetToNextIfd() {
+ return mOffsetToNextIfd;
+ }
+
+ /**
+ * Returns true if all tags in this two IFDs are equal. Note that tags of
+ * IFDs offset or thumbnail offset will be ignored.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof IfdData) {
+ IfdData data = (IfdData) obj;
+ if (data.getId() == mIfdId && data.getTagCount() == getTagCount()) {
+ ExifTag[] tags = data.getAllTags();
+ for (ExifTag tag : tags) {
+ if (ExifInterface.isOffsetTag(tag.getTagId())) {
+ continue;
+ }
+ ExifTag tag2 = mExifTags.get(tag.getTagId());
+ if (!tag.equals(tag2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdId.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdId.java
new file mode 100644
index 0000000..7842edb
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/IfdId.java
@@ -0,0 +1,31 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+/**
+ * The constants of the IFD ID defined in EXIF spec.
+ */
+public interface IfdId {
+ public static final int TYPE_IFD_0 = 0;
+ public static final int TYPE_IFD_1 = 1;
+ public static final int TYPE_IFD_EXIF = 2;
+ public static final int TYPE_IFD_INTEROPERABILITY = 3;
+ public static final int TYPE_IFD_GPS = 4;
+ /* This is used in ExifData to allocate enough IfdData */
+ static final int TYPE_IFD_COUNT = 5;
+
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/JpegHeader.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/JpegHeader.java
new file mode 100644
index 0000000..e3e787e
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/JpegHeader.java
@@ -0,0 +1,39 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+class JpegHeader {
+ public static final short SOI = (short) 0xFFD8;
+ public static final short APP1 = (short) 0xFFE1;
+ public static final short APP0 = (short) 0xFFE0;
+ public static final short EOI = (short) 0xFFD9;
+
+ /**
+ * SOF (start of frame). All value between SOF0 and SOF15 is SOF marker except for DHT, JPG,
+ * and DAC marker.
+ */
+ public static final short SOF0 = (short) 0xFFC0;
+ public static final short SOF15 = (short) 0xFFCF;
+ public static final short DHT = (short) 0xFFC4;
+ public static final short JPG = (short) 0xFFC8;
+ public static final short DAC = (short) 0xFFCC;
+
+ public static final boolean isSofMarker(short marker) {
+ return marker >= SOF0 && marker <= SOF15 && marker != DHT && marker != JPG
+ && marker != DAC;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/OrderedDataOutputStream.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/OrderedDataOutputStream.java
new file mode 100644
index 0000000..428e6b9
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/OrderedDataOutputStream.java
@@ -0,0 +1,56 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+class OrderedDataOutputStream extends FilterOutputStream {
+ private final ByteBuffer mByteBuffer = ByteBuffer.allocate(4);
+
+ public OrderedDataOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ public OrderedDataOutputStream setByteOrder(ByteOrder order) {
+ mByteBuffer.order(order);
+ return this;
+ }
+
+ public OrderedDataOutputStream writeShort(short value) throws IOException {
+ mByteBuffer.rewind();
+ mByteBuffer.putShort(value);
+ out.write(mByteBuffer.array(), 0, 2);
+ return this;
+ }
+
+ public OrderedDataOutputStream writeInt(int value) throws IOException {
+ mByteBuffer.rewind();
+ mByteBuffer.putInt(value);
+ out.write(mByteBuffer.array());
+ return this;
+ }
+
+ public OrderedDataOutputStream writeRational(Rational rational) throws IOException {
+ writeInt((int) rational.getNumerator());
+ writeInt((int) rational.getDenominator());
+ return this;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/exif/Rational.java b/packages/WallpaperCropper/src/com/android/gallery3d/exif/Rational.java
new file mode 100644
index 0000000..591d63f
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/exif/Rational.java
@@ -0,0 +1,88 @@
+/*
+ * 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 com.android.gallery3d.exif;
+
+/**
+ * The rational data type of EXIF tag. Contains a pair of longs representing the
+ * numerator and denominator of a Rational number.
+ */
+public class Rational {
+
+ private final long mNumerator;
+ private final long mDenominator;
+
+ /**
+ * Create a Rational with a given numerator and denominator.
+ *
+ * @param nominator
+ * @param denominator
+ */
+ public Rational(long nominator, long denominator) {
+ mNumerator = nominator;
+ mDenominator = denominator;
+ }
+
+ /**
+ * Create a copy of a Rational.
+ */
+ public Rational(Rational r) {
+ mNumerator = r.mNumerator;
+ mDenominator = r.mDenominator;
+ }
+
+ /**
+ * Gets the numerator of the rational.
+ */
+ public long getNumerator() {
+ return mNumerator;
+ }
+
+ /**
+ * Gets the denominator of the rational
+ */
+ public long getDenominator() {
+ return mDenominator;
+ }
+
+ /**
+ * Gets the rational value as type double. Will cause a divide-by-zero error
+ * if the denominator is 0.
+ */
+ public double toDouble() {
+ return mNumerator / (double) mDenominator;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof Rational) {
+ Rational data = (Rational) obj;
+ return mNumerator == data.mNumerator && mDenominator == data.mDenominator;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return mNumerator + "/" + mDenominator;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BasicTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BasicTexture.java
new file mode 100644
index 0000000..2e77b90
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BasicTexture.java
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.util.Log;
+
+import com.android.gallery3d.common.Utils;
+
+import java.util.WeakHashMap;
+
+// BasicTexture is a Texture corresponds to a real GL texture.
+// The state of a BasicTexture indicates whether its data is loaded to GL memory.
+// If a BasicTexture is loaded into GL memory, it has a GL texture id.
+public abstract class BasicTexture implements Texture {
+
+ @SuppressWarnings("unused")
+ private static final String TAG = "BasicTexture";
+ protected static final int UNSPECIFIED = -1;
+
+ protected static final int STATE_UNLOADED = 0;
+ protected static final int STATE_LOADED = 1;
+ protected static final int STATE_ERROR = -1;
+
+ // Log a warning if a texture is larger along a dimension
+ private static final int MAX_TEXTURE_SIZE = 4096;
+
+ protected int mId = -1;
+ protected int mState;
+
+ protected int mWidth = UNSPECIFIED;
+ protected int mHeight = UNSPECIFIED;
+
+ protected int mTextureWidth;
+ protected int mTextureHeight;
+
+ private boolean mHasBorder;
+
+ protected GLCanvas mCanvasRef = null;
+ private static WeakHashMap<BasicTexture, Object> sAllTextures
+ = new WeakHashMap<BasicTexture, Object>();
+ private static ThreadLocal sInFinalizer = new ThreadLocal();
+
+ protected BasicTexture(GLCanvas canvas, int id, int state) {
+ setAssociatedCanvas(canvas);
+ mId = id;
+ mState = state;
+ synchronized (sAllTextures) {
+ sAllTextures.put(this, null);
+ }
+ }
+
+ protected BasicTexture() {
+ this(null, 0, STATE_UNLOADED);
+ }
+
+ protected void setAssociatedCanvas(GLCanvas canvas) {
+ mCanvasRef = canvas;
+ }
+
+ /**
+ * Sets the content size of this texture. In OpenGL, the actual texture
+ * size must be of power of 2, the size of the content may be smaller.
+ */
+ public void setSize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ mTextureWidth = width > 0 ? Utils.nextPowerOf2(width) : 0;
+ mTextureHeight = height > 0 ? Utils.nextPowerOf2(height) : 0;
+ if (mTextureWidth > MAX_TEXTURE_SIZE || mTextureHeight > MAX_TEXTURE_SIZE) {
+ Log.w(TAG, String.format("texture is too large: %d x %d",
+ mTextureWidth, mTextureHeight), new Exception());
+ }
+ }
+
+ public boolean isFlippedVertically() {
+ return false;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ @Override
+ public int getWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getHeight() {
+ return mHeight;
+ }
+
+ // Returns the width rounded to the next power of 2.
+ public int getTextureWidth() {
+ return mTextureWidth;
+ }
+
+ // Returns the height rounded to the next power of 2.
+ public int getTextureHeight() {
+ return mTextureHeight;
+ }
+
+ // Returns true if the texture has one pixel transparent border around the
+ // actual content. This is used to avoid jigged edges.
+ //
+ // The jigged edges appear because we use GL_CLAMP_TO_EDGE for texture wrap
+ // mode (GL_CLAMP is not available in OpenGL ES), so a pixel partially
+ // covered by the texture will use the color of the edge texel. If we add
+ // the transparent border, the color of the edge texel will be mixed with
+ // appropriate amount of transparent.
+ //
+ // Currently our background is black, so we can draw the thumbnails without
+ // enabling blending.
+ public boolean hasBorder() {
+ return mHasBorder;
+ }
+
+ protected void setBorder(boolean hasBorder) {
+ mHasBorder = hasBorder;
+ }
+
+ @Override
+ public void draw(GLCanvas canvas, int x, int y) {
+ canvas.drawTexture(this, x, y, getWidth(), getHeight());
+ }
+
+ @Override
+ public void draw(GLCanvas canvas, int x, int y, int w, int h) {
+ canvas.drawTexture(this, x, y, w, h);
+ }
+
+ // onBind is called before GLCanvas binds this texture.
+ // It should make sure the data is uploaded to GL memory.
+ abstract protected boolean onBind(GLCanvas canvas);
+
+ // Returns the GL texture target for this texture (e.g. GL_TEXTURE_2D).
+ abstract protected int getTarget();
+
+ public boolean isLoaded() {
+ return mState == STATE_LOADED;
+ }
+
+ // recycle() is called when the texture will never be used again,
+ // so it can free all resources.
+ public void recycle() {
+ freeResource();
+ }
+
+ // yield() is called when the texture will not be used temporarily,
+ // so it can free some resources.
+ // The default implementation unloads the texture from GL memory, so
+ // the subclass should make sure it can reload the texture to GL memory
+ // later, or it will have to override this method.
+ public void yield() {
+ freeResource();
+ }
+
+ private void freeResource() {
+ GLCanvas canvas = mCanvasRef;
+ if (canvas != null && mId != -1) {
+ canvas.unloadTexture(this);
+ mId = -1; // Don't free it again.
+ }
+ mState = STATE_UNLOADED;
+ setAssociatedCanvas(null);
+ }
+
+ @Override
+ protected void finalize() {
+ sInFinalizer.set(BasicTexture.class);
+ recycle();
+ sInFinalizer.set(null);
+ }
+
+ // This is for deciding if we can call Bitmap's recycle().
+ // We cannot call Bitmap's recycle() in finalizer because at that point
+ // the finalizer of Bitmap may already be called so recycle() will crash.
+ public static boolean inFinalizer() {
+ return sInFinalizer.get() != null;
+ }
+
+ public static void yieldAllTextures() {
+ synchronized (sAllTextures) {
+ for (BasicTexture t : sAllTextures.keySet()) {
+ t.yield();
+ }
+ }
+ }
+
+ public static void invalidateAllTextures() {
+ synchronized (sAllTextures) {
+ for (BasicTexture t : sAllTextures.keySet()) {
+ t.mState = STATE_UNLOADED;
+ t.setAssociatedCanvas(null);
+ }
+ }
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
new file mode 100644
index 0000000..100b0b3b
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+
+import junit.framework.Assert;
+
+// BitmapTexture is a texture whose content is specified by a fixed Bitmap.
+//
+// The texture does not own the Bitmap. The user should make sure the Bitmap
+// is valid during the texture's lifetime. When the texture is recycled, it
+// does not free the Bitmap.
+public class BitmapTexture extends UploadedTexture {
+ protected Bitmap mContentBitmap;
+
+ public BitmapTexture(Bitmap bitmap) {
+ this(bitmap, false);
+ }
+
+ public BitmapTexture(Bitmap bitmap, boolean hasBorder) {
+ super(hasBorder);
+ Assert.assertTrue(bitmap != null && !bitmap.isRecycled());
+ mContentBitmap = bitmap;
+ }
+
+ @Override
+ protected void onFreeBitmap(Bitmap bitmap) {
+ // Do nothing.
+ }
+
+ @Override
+ protected Bitmap onGetBitmap() {
+ return mContentBitmap;
+ }
+
+ public Bitmap getBitmap() {
+ return mContentBitmap;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLCanvas.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLCanvas.java
new file mode 100644
index 0000000..305e905
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLCanvas.java
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+import javax.microedition.khronos.opengles.GL11;
+
+//
+// GLCanvas gives a convenient interface to draw using OpenGL.
+//
+// When a rectangle is specified in this interface, it means the region
+// [x, x+width) * [y, y+height)
+//
+public interface GLCanvas {
+
+ public GLId getGLId();
+
+ // Tells GLCanvas the size of the underlying GL surface. This should be
+ // called before first drawing and when the size of GL surface is changed.
+ // This is called by GLRoot and should not be called by the clients
+ // who only want to draw on the GLCanvas. Both width and height must be
+ // nonnegative.
+ public abstract void setSize(int width, int height);
+
+ // Clear the drawing buffers. This should only be used by GLRoot.
+ public abstract void clearBuffer();
+
+ public abstract void clearBuffer(float[] argb);
+
+ // Sets and gets the current alpha, alpha must be in [0, 1].
+ public abstract void setAlpha(float alpha);
+
+ public abstract float getAlpha();
+
+ // (current alpha) = (current alpha) * alpha
+ public abstract void multiplyAlpha(float alpha);
+
+ // Change the current transform matrix.
+ public abstract void translate(float x, float y, float z);
+
+ public abstract void translate(float x, float y);
+
+ public abstract void scale(float sx, float sy, float sz);
+
+ public abstract void rotate(float angle, float x, float y, float z);
+
+ public abstract void multiplyMatrix(float[] mMatrix, int offset);
+
+ // Pushes the configuration state (matrix, and alpha) onto
+ // a private stack.
+ public abstract void save();
+
+ // Same as save(), but only save those specified in saveFlags.
+ public abstract void save(int saveFlags);
+
+ public static final int SAVE_FLAG_ALL = 0xFFFFFFFF;
+ public static final int SAVE_FLAG_ALPHA = 0x01;
+ public static final int SAVE_FLAG_MATRIX = 0x02;
+
+ // Pops from the top of the stack as current configuration state (matrix,
+ // alpha, and clip). This call balances a previous call to save(), and is
+ // used to remove all modifications to the configuration state since the
+ // last save call.
+ public abstract void restore();
+
+ // Draws a line using the specified paint from (x1, y1) to (x2, y2).
+ // (Both end points are included).
+ public abstract void drawLine(float x1, float y1, float x2, float y2, GLPaint paint);
+
+ // Draws a rectangle using the specified paint from (x1, y1) to (x2, y2).
+ // (Both end points are included).
+ public abstract void drawRect(float x1, float y1, float x2, float y2, GLPaint paint);
+
+ // Fills the specified rectangle with the specified color.
+ public abstract void fillRect(float x, float y, float width, float height, int color);
+
+ // Draws a texture to the specified rectangle.
+ public abstract void drawTexture(
+ BasicTexture texture, int x, int y, int width, int height);
+
+ public abstract void drawMesh(BasicTexture tex, int x, int y, int xyBuffer,
+ int uvBuffer, int indexBuffer, int indexCount);
+
+ // Draws the source rectangle part of the texture to the target rectangle.
+ public abstract void drawTexture(BasicTexture texture, RectF source, RectF target);
+
+ // Draw a texture with a specified texture transform.
+ public abstract void drawTexture(BasicTexture texture, float[] mTextureTransform,
+ int x, int y, int w, int h);
+
+ // Draw two textures to the specified rectangle. The actual texture used is
+ // from * (1 - ratio) + to * ratio
+ // The two textures must have the same size.
+ public abstract void drawMixed(BasicTexture from, int toColor,
+ float ratio, int x, int y, int w, int h);
+
+ // Draw a region of a texture and a specified color to the specified
+ // rectangle. The actual color used is from * (1 - ratio) + to * ratio.
+ // The region of the texture is defined by parameter "src". The target
+ // rectangle is specified by parameter "target".
+ public abstract void drawMixed(BasicTexture from, int toColor,
+ float ratio, RectF src, RectF target);
+
+ // Unloads the specified texture from the canvas. The resource allocated
+ // to draw the texture will be released. The specified texture will return
+ // to the unloaded state. This function should be called only from
+ // BasicTexture or its descendant
+ public abstract boolean unloadTexture(BasicTexture texture);
+
+ // Delete the specified buffer object, similar to unloadTexture.
+ public abstract void deleteBuffer(int bufferId);
+
+ // Delete the textures and buffers in GL side. This function should only be
+ // called in the GL thread.
+ public abstract void deleteRecycledResources();
+
+ // Dump statistics information and clear the counters. For debug only.
+ public abstract void dumpStatisticsAndClear();
+
+ public abstract void beginRenderTarget(RawTexture texture);
+
+ public abstract void endRenderTarget();
+
+ /**
+ * Sets texture parameters to use GL_CLAMP_TO_EDGE for both
+ * GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T. Sets texture parameters to be
+ * GL_LINEAR for GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER.
+ * bindTexture() must be called prior to this.
+ *
+ * @param texture The texture to set parameters on.
+ */
+ public abstract void setTextureParameters(BasicTexture texture);
+
+ /**
+ * Initializes the texture to a size by calling texImage2D on it.
+ *
+ * @param texture The texture to initialize the size.
+ * @param format The texture format (e.g. GL_RGBA)
+ * @param type The texture type (e.g. GL_UNSIGNED_BYTE)
+ */
+ public abstract void initializeTextureSize(BasicTexture texture, int format, int type);
+
+ /**
+ * Initializes the texture to a size by calling texImage2D on it.
+ *
+ * @param texture The texture to initialize the size.
+ * @param bitmap The bitmap to initialize the bitmap with.
+ */
+ public abstract void initializeTexture(BasicTexture texture, Bitmap bitmap);
+
+ /**
+ * Calls glTexSubImage2D to upload a bitmap to the texture.
+ *
+ * @param texture The target texture to write to.
+ * @param xOffset Specifies a texel offset in the x direction within the
+ * texture array.
+ * @param yOffset Specifies a texel offset in the y direction within the
+ * texture array.
+ * @param format The texture format (e.g. GL_RGBA)
+ * @param type The texture type (e.g. GL_UNSIGNED_BYTE)
+ */
+ public abstract void texSubImage2D(BasicTexture texture, int xOffset, int yOffset,
+ Bitmap bitmap,
+ int format, int type);
+
+ /**
+ * Generates buffers and uploads the buffer data.
+ *
+ * @param buffer The buffer to upload
+ * @return The buffer ID that was generated.
+ */
+ public abstract int uploadBuffer(java.nio.FloatBuffer buffer);
+
+ /**
+ * Generates buffers and uploads the element array buffer data.
+ *
+ * @param buffer The buffer to upload
+ * @return The buffer ID that was generated.
+ */
+ public abstract int uploadBuffer(java.nio.ByteBuffer buffer);
+
+ /**
+ * After LightCycle makes GL calls, this method is called to restore the GL
+ * configuration to the one expected by GLCanvas.
+ */
+ public abstract void recoverFromLightCycle();
+
+ /**
+ * Gets the bounds given by x, y, width, and height as well as the internal
+ * matrix state. There is no special handling for non-90-degree rotations.
+ * It only considers the lower-left and upper-right corners as the bounds.
+ *
+ * @param bounds The output bounds to write to.
+ * @param x The left side of the input rectangle.
+ * @param y The bottom of the input rectangle.
+ * @param width The width of the input rectangle.
+ * @param height The height of the input rectangle.
+ */
+ public abstract void getBounds(Rect bounds, int x, int y, int width, int height);
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
new file mode 100644
index 0000000..4ead131
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
@@ -0,0 +1,1009 @@
+/*
+ * 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 com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.opengl.GLES20;
+import android.opengl.GLUtils;
+import android.opengl.Matrix;
+import android.util.Log;
+
+import com.android.gallery3d.util.IntArray;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class GLES20Canvas implements GLCanvas {
+ // ************** Constants **********************
+ private static final String TAG = GLES20Canvas.class.getSimpleName();
+ private static final int FLOAT_SIZE = Float.SIZE / Byte.SIZE;
+ private static final float OPAQUE_ALPHA = 0.95f;
+
+ private static final int COORDS_PER_VERTEX = 2;
+ private static final int VERTEX_STRIDE = COORDS_PER_VERTEX * FLOAT_SIZE;
+
+ private static final int COUNT_FILL_VERTEX = 4;
+ private static final int COUNT_LINE_VERTEX = 2;
+ private static final int COUNT_RECT_VERTEX = 4;
+ private static final int OFFSET_FILL_RECT = 0;
+ private static final int OFFSET_DRAW_LINE = OFFSET_FILL_RECT + COUNT_FILL_VERTEX;
+ private static final int OFFSET_DRAW_RECT = OFFSET_DRAW_LINE + COUNT_LINE_VERTEX;
+
+ private static final float[] BOX_COORDINATES = {
+ 0, 0, // Fill rectangle
+ 1, 0,
+ 0, 1,
+ 1, 1,
+ 0, 0, // Draw line
+ 1, 1,
+ 0, 0, // Draw rectangle outline
+ 0, 1,
+ 1, 1,
+ 1, 0,
+ };
+
+ private static final float[] BOUNDS_COORDINATES = {
+ 0, 0, 0, 1,
+ 1, 1, 0, 1,
+ };
+
+ private static final String POSITION_ATTRIBUTE = "aPosition";
+ private static final String COLOR_UNIFORM = "uColor";
+ private static final String MATRIX_UNIFORM = "uMatrix";
+ private static final String TEXTURE_MATRIX_UNIFORM = "uTextureMatrix";
+ private static final String TEXTURE_SAMPLER_UNIFORM = "uTextureSampler";
+ private static final String ALPHA_UNIFORM = "uAlpha";
+ private static final String TEXTURE_COORD_ATTRIBUTE = "aTextureCoordinate";
+
+ private static final String DRAW_VERTEX_SHADER = ""
+ + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
+ + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
+ + "void main() {\n"
+ + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
+ + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
+ + "}\n";
+
+ private static final String DRAW_FRAGMENT_SHADER = ""
+ + "precision mediump float;\n"
+ + "uniform vec4 " + COLOR_UNIFORM + ";\n"
+ + "void main() {\n"
+ + " gl_FragColor = " + COLOR_UNIFORM + ";\n"
+ + "}\n";
+
+ private static final String TEXTURE_VERTEX_SHADER = ""
+ + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
+ + "uniform mat4 " + TEXTURE_MATRIX_UNIFORM + ";\n"
+ + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "void main() {\n"
+ + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
+ + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
+ + " vTextureCoord = (" + TEXTURE_MATRIX_UNIFORM + " * pos).xy;\n"
+ + "}\n";
+
+ private static final String MESH_VERTEX_SHADER = ""
+ + "uniform mat4 " + MATRIX_UNIFORM + ";\n"
+ + "attribute vec2 " + POSITION_ATTRIBUTE + ";\n"
+ + "attribute vec2 " + TEXTURE_COORD_ATTRIBUTE + ";\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "void main() {\n"
+ + " vec4 pos = vec4(" + POSITION_ATTRIBUTE + ", 0.0, 1.0);\n"
+ + " gl_Position = " + MATRIX_UNIFORM + " * pos;\n"
+ + " vTextureCoord = " + TEXTURE_COORD_ATTRIBUTE + ";\n"
+ + "}\n";
+
+ private static final String TEXTURE_FRAGMENT_SHADER = ""
+ + "precision mediump float;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "uniform float " + ALPHA_UNIFORM + ";\n"
+ + "uniform sampler2D " + TEXTURE_SAMPLER_UNIFORM + ";\n"
+ + "void main() {\n"
+ + " gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n"
+ + " gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
+ + "}\n";
+
+ private static final String OES_TEXTURE_FRAGMENT_SHADER = ""
+ + "#extension GL_OES_EGL_image_external : require\n"
+ + "precision mediump float;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "uniform float " + ALPHA_UNIFORM + ";\n"
+ + "uniform samplerExternalOES " + TEXTURE_SAMPLER_UNIFORM + ";\n"
+ + "void main() {\n"
+ + " gl_FragColor = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", vTextureCoord);\n"
+ + " gl_FragColor *= " + ALPHA_UNIFORM + ";\n"
+ + "}\n";
+
+ private static final int INITIAL_RESTORE_STATE_SIZE = 8;
+ private static final int MATRIX_SIZE = 16;
+
+ // Keep track of restore state
+ private float[] mMatrices = new float[INITIAL_RESTORE_STATE_SIZE * MATRIX_SIZE];
+ private float[] mAlphas = new float[INITIAL_RESTORE_STATE_SIZE];
+ private IntArray mSaveFlags = new IntArray();
+
+ private int mCurrentAlphaIndex = 0;
+ private int mCurrentMatrixIndex = 0;
+
+ // Viewport size
+ private int mWidth;
+ private int mHeight;
+
+ // Projection matrix
+ private float[] mProjectionMatrix = new float[MATRIX_SIZE];
+
+ // Screen size for when we aren't bound to a texture
+ private int mScreenWidth;
+ private int mScreenHeight;
+
+ // GL programs
+ private int mDrawProgram;
+ private int mTextureProgram;
+ private int mOesTextureProgram;
+ private int mMeshProgram;
+
+ // GL buffer containing BOX_COORDINATES
+ private int mBoxCoordinates;
+
+ // Handle indices -- common
+ private static final int INDEX_POSITION = 0;
+ private static final int INDEX_MATRIX = 1;
+
+ // Handle indices -- draw
+ private static final int INDEX_COLOR = 2;
+
+ // Handle indices -- texture
+ private static final int INDEX_TEXTURE_MATRIX = 2;
+ private static final int INDEX_TEXTURE_SAMPLER = 3;
+ private static final int INDEX_ALPHA = 4;
+
+ // Handle indices -- mesh
+ private static final int INDEX_TEXTURE_COORD = 2;
+
+ private abstract static class ShaderParameter {
+ public int handle;
+ protected final String mName;
+
+ public ShaderParameter(String name) {
+ mName = name;
+ }
+
+ public abstract void loadHandle(int program);
+ }
+
+ private static class UniformShaderParameter extends ShaderParameter {
+ public UniformShaderParameter(String name) {
+ super(name);
+ }
+
+ @Override
+ public void loadHandle(int program) {
+ handle = GLES20.glGetUniformLocation(program, mName);
+ checkError();
+ }
+ }
+
+ private static class AttributeShaderParameter extends ShaderParameter {
+ public AttributeShaderParameter(String name) {
+ super(name);
+ }
+
+ @Override
+ public void loadHandle(int program) {
+ handle = GLES20.glGetAttribLocation(program, mName);
+ checkError();
+ }
+ }
+
+ ShaderParameter[] mDrawParameters = {
+ new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+ new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+ new UniformShaderParameter(COLOR_UNIFORM), // INDEX_COLOR
+ };
+ ShaderParameter[] mTextureParameters = {
+ new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+ new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+ new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
+ new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
+ new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
+ };
+ ShaderParameter[] mOesTextureParameters = {
+ new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+ new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+ new UniformShaderParameter(TEXTURE_MATRIX_UNIFORM), // INDEX_TEXTURE_MATRIX
+ new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
+ new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
+ };
+ ShaderParameter[] mMeshParameters = {
+ new AttributeShaderParameter(POSITION_ATTRIBUTE), // INDEX_POSITION
+ new UniformShaderParameter(MATRIX_UNIFORM), // INDEX_MATRIX
+ new AttributeShaderParameter(TEXTURE_COORD_ATTRIBUTE), // INDEX_TEXTURE_COORD
+ new UniformShaderParameter(TEXTURE_SAMPLER_UNIFORM), // INDEX_TEXTURE_SAMPLER
+ new UniformShaderParameter(ALPHA_UNIFORM), // INDEX_ALPHA
+ };
+
+ private final IntArray mUnboundTextures = new IntArray();
+ private final IntArray mDeleteBuffers = new IntArray();
+
+ // Keep track of statistics for debugging
+ private int mCountDrawMesh = 0;
+ private int mCountTextureRect = 0;
+ private int mCountFillRect = 0;
+ private int mCountDrawLine = 0;
+
+ // Buffer for framebuffer IDs -- we keep track so we can switch the attached
+ // texture.
+ private int[] mFrameBuffer = new int[1];
+
+ // Bound textures.
+ private ArrayList<RawTexture> mTargetTextures = new ArrayList<RawTexture>();
+
+ // Temporary variables used within calculations
+ private final float[] mTempMatrix = new float[32];
+ private final float[] mTempColor = new float[4];
+ private final RectF mTempSourceRect = new RectF();
+ private final RectF mTempTargetRect = new RectF();
+ private final float[] mTempTextureMatrix = new float[MATRIX_SIZE];
+ private final int[] mTempIntArray = new int[1];
+
+ private static final GLId mGLId = new GLES20IdImpl();
+
+ public GLES20Canvas() {
+ Matrix.setIdentityM(mTempTextureMatrix, 0);
+ Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
+ mAlphas[mCurrentAlphaIndex] = 1f;
+ mTargetTextures.add(null);
+
+ FloatBuffer boxBuffer = createBuffer(BOX_COORDINATES);
+ mBoxCoordinates = uploadBuffer(boxBuffer);
+
+ int drawVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DRAW_VERTEX_SHADER);
+ int textureVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, TEXTURE_VERTEX_SHADER);
+ int meshVertexShader = loadShader(GLES20.GL_VERTEX_SHADER, MESH_VERTEX_SHADER);
+ int drawFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, DRAW_FRAGMENT_SHADER);
+ int textureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, TEXTURE_FRAGMENT_SHADER);
+ int oesTextureFragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
+ OES_TEXTURE_FRAGMENT_SHADER);
+
+ mDrawProgram = assembleProgram(drawVertexShader, drawFragmentShader, mDrawParameters);
+ mTextureProgram = assembleProgram(textureVertexShader, textureFragmentShader,
+ mTextureParameters);
+ mOesTextureProgram = assembleProgram(textureVertexShader, oesTextureFragmentShader,
+ mOesTextureParameters);
+ mMeshProgram = assembleProgram(meshVertexShader, textureFragmentShader, mMeshParameters);
+ GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
+ checkError();
+ }
+
+ private static FloatBuffer createBuffer(float[] values) {
+ // First create an nio buffer, then create a VBO from it.
+ int size = values.length * FLOAT_SIZE;
+ FloatBuffer buffer = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder())
+ .asFloatBuffer();
+ buffer.put(values, 0, values.length).position(0);
+ return buffer;
+ }
+
+ private int assembleProgram(int vertexShader, int fragmentShader, ShaderParameter[] params) {
+ int program = GLES20.glCreateProgram();
+ checkError();
+ if (program == 0) {
+ throw new RuntimeException("Cannot create GL program: " + GLES20.glGetError());
+ }
+ GLES20.glAttachShader(program, vertexShader);
+ checkError();
+ GLES20.glAttachShader(program, fragmentShader);
+ checkError();
+ GLES20.glLinkProgram(program);
+ checkError();
+ int[] mLinkStatus = mTempIntArray;
+ GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, mLinkStatus, 0);
+ if (mLinkStatus[0] != GLES20.GL_TRUE) {
+ Log.e(TAG, "Could not link program: ");
+ Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+ GLES20.glDeleteProgram(program);
+ program = 0;
+ }
+ for (int i = 0; i < params.length; i++) {
+ params[i].loadHandle(program);
+ }
+ return program;
+ }
+
+ private static int loadShader(int type, String shaderCode) {
+ // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
+ // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
+ int shader = GLES20.glCreateShader(type);
+
+ // add the source code to the shader and compile it
+ GLES20.glShaderSource(shader, shaderCode);
+ checkError();
+ GLES20.glCompileShader(shader);
+ checkError();
+
+ return shader;
+ }
+
+ @Override
+ public void setSize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ GLES20.glViewport(0, 0, mWidth, mHeight);
+ checkError();
+ Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
+ Matrix.orthoM(mProjectionMatrix, 0, 0, width, 0, height, -1, 1);
+ if (getTargetTexture() == null) {
+ mScreenWidth = width;
+ mScreenHeight = height;
+ Matrix.translateM(mMatrices, mCurrentMatrixIndex, 0, height, 0);
+ Matrix.scaleM(mMatrices, mCurrentMatrixIndex, 1, -1, 1);
+ }
+ }
+
+ @Override
+ public void clearBuffer() {
+ GLES20.glClearColor(0f, 0f, 0f, 1f);
+ checkError();
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ checkError();
+ }
+
+ @Override
+ public void clearBuffer(float[] argb) {
+ GLES20.glClearColor(argb[1], argb[2], argb[3], argb[0]);
+ checkError();
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ checkError();
+ }
+
+ @Override
+ public float getAlpha() {
+ return mAlphas[mCurrentAlphaIndex];
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ mAlphas[mCurrentAlphaIndex] = alpha;
+ }
+
+ @Override
+ public void multiplyAlpha(float alpha) {
+ setAlpha(getAlpha() * alpha);
+ }
+
+ @Override
+ public void translate(float x, float y, float z) {
+ Matrix.translateM(mMatrices, mCurrentMatrixIndex, x, y, z);
+ }
+
+ // This is a faster version of translate(x, y, z) because
+ // (1) we knows z = 0, (2) we inline the Matrix.translateM call,
+ // (3) we unroll the loop
+ @Override
+ public void translate(float x, float y) {
+ int index = mCurrentMatrixIndex;
+ float[] m = mMatrices;
+ m[index + 12] += m[index + 0] * x + m[index + 4] * y;
+ m[index + 13] += m[index + 1] * x + m[index + 5] * y;
+ m[index + 14] += m[index + 2] * x + m[index + 6] * y;
+ m[index + 15] += m[index + 3] * x + m[index + 7] * y;
+ }
+
+ @Override
+ public void scale(float sx, float sy, float sz) {
+ Matrix.scaleM(mMatrices, mCurrentMatrixIndex, sx, sy, sz);
+ }
+
+ @Override
+ public void rotate(float angle, float x, float y, float z) {
+ if (angle == 0f) {
+ return;
+ }
+ float[] temp = mTempMatrix;
+ Matrix.setRotateM(temp, 0, angle, x, y, z);
+ float[] matrix = mMatrices;
+ int index = mCurrentMatrixIndex;
+ Matrix.multiplyMM(temp, MATRIX_SIZE, matrix, index, temp, 0);
+ System.arraycopy(temp, MATRIX_SIZE, matrix, index, MATRIX_SIZE);
+ }
+
+ @Override
+ public void multiplyMatrix(float[] matrix, int offset) {
+ float[] temp = mTempMatrix;
+ float[] currentMatrix = mMatrices;
+ int index = mCurrentMatrixIndex;
+ Matrix.multiplyMM(temp, 0, currentMatrix, index, matrix, offset);
+ System.arraycopy(temp, 0, currentMatrix, index, 16);
+ }
+
+ @Override
+ public void save() {
+ save(SAVE_FLAG_ALL);
+ }
+
+ @Override
+ public void save(int saveFlags) {
+ boolean saveAlpha = (saveFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
+ if (saveAlpha) {
+ float currentAlpha = getAlpha();
+ mCurrentAlphaIndex++;
+ if (mAlphas.length <= mCurrentAlphaIndex) {
+ mAlphas = Arrays.copyOf(mAlphas, mAlphas.length * 2);
+ }
+ mAlphas[mCurrentAlphaIndex] = currentAlpha;
+ }
+ boolean saveMatrix = (saveFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
+ if (saveMatrix) {
+ int currentIndex = mCurrentMatrixIndex;
+ mCurrentMatrixIndex += MATRIX_SIZE;
+ if (mMatrices.length <= mCurrentMatrixIndex) {
+ mMatrices = Arrays.copyOf(mMatrices, mMatrices.length * 2);
+ }
+ System.arraycopy(mMatrices, currentIndex, mMatrices, mCurrentMatrixIndex, MATRIX_SIZE);
+ }
+ mSaveFlags.add(saveFlags);
+ }
+
+ @Override
+ public void restore() {
+ int restoreFlags = mSaveFlags.removeLast();
+ boolean restoreAlpha = (restoreFlags & SAVE_FLAG_ALPHA) == SAVE_FLAG_ALPHA;
+ if (restoreAlpha) {
+ mCurrentAlphaIndex--;
+ }
+ boolean restoreMatrix = (restoreFlags & SAVE_FLAG_MATRIX) == SAVE_FLAG_MATRIX;
+ if (restoreMatrix) {
+ mCurrentMatrixIndex -= MATRIX_SIZE;
+ }
+ }
+
+ @Override
+ public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {
+ draw(GLES20.GL_LINE_STRIP, OFFSET_DRAW_LINE, COUNT_LINE_VERTEX, x1, y1, x2 - x1, y2 - y1,
+ paint);
+ mCountDrawLine++;
+ }
+
+ @Override
+ public void drawRect(float x, float y, float width, float height, GLPaint paint) {
+ draw(GLES20.GL_LINE_LOOP, OFFSET_DRAW_RECT, COUNT_RECT_VERTEX, x, y, width, height, paint);
+ mCountDrawLine++;
+ }
+
+ private void draw(int type, int offset, int count, float x, float y, float width, float height,
+ GLPaint paint) {
+ draw(type, offset, count, x, y, width, height, paint.getColor(), paint.getLineWidth());
+ }
+
+ private void draw(int type, int offset, int count, float x, float y, float width, float height,
+ int color, float lineWidth) {
+ prepareDraw(offset, color, lineWidth);
+ draw(mDrawParameters, type, count, x, y, width, height);
+ }
+
+ private void prepareDraw(int offset, int color, float lineWidth) {
+ GLES20.glUseProgram(mDrawProgram);
+ checkError();
+ if (lineWidth > 0) {
+ GLES20.glLineWidth(lineWidth);
+ checkError();
+ }
+ float[] colorArray = getColor(color);
+ boolean blendingEnabled = (colorArray[3] < 1f);
+ enableBlending(blendingEnabled);
+ if (blendingEnabled) {
+ GLES20.glBlendColor(colorArray[0], colorArray[1], colorArray[2], colorArray[3]);
+ checkError();
+ }
+
+ GLES20.glUniform4fv(mDrawParameters[INDEX_COLOR].handle, 1, colorArray, 0);
+ setPosition(mDrawParameters, offset);
+ checkError();
+ }
+
+ private float[] getColor(int color) {
+ float alpha = ((color >>> 24) & 0xFF) / 255f * getAlpha();
+ float red = ((color >>> 16) & 0xFF) / 255f * alpha;
+ float green = ((color >>> 8) & 0xFF) / 255f * alpha;
+ float blue = (color & 0xFF) / 255f * alpha;
+ mTempColor[0] = red;
+ mTempColor[1] = green;
+ mTempColor[2] = blue;
+ mTempColor[3] = alpha;
+ return mTempColor;
+ }
+
+ private void enableBlending(boolean enableBlending) {
+ if (enableBlending) {
+ GLES20.glEnable(GLES20.GL_BLEND);
+ checkError();
+ } else {
+ GLES20.glDisable(GLES20.GL_BLEND);
+ checkError();
+ }
+ }
+
+ private void setPosition(ShaderParameter[] params, int offset) {
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mBoxCoordinates);
+ checkError();
+ GLES20.glVertexAttribPointer(params[INDEX_POSITION].handle, COORDS_PER_VERTEX,
+ GLES20.GL_FLOAT, false, VERTEX_STRIDE, offset * VERTEX_STRIDE);
+ checkError();
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+ checkError();
+ }
+
+ private void draw(ShaderParameter[] params, int type, int count, float x, float y, float width,
+ float height) {
+ setMatrix(params, x, y, width, height);
+ int positionHandle = params[INDEX_POSITION].handle;
+ GLES20.glEnableVertexAttribArray(positionHandle);
+ checkError();
+ GLES20.glDrawArrays(type, 0, count);
+ checkError();
+ GLES20.glDisableVertexAttribArray(positionHandle);
+ checkError();
+ }
+
+ private void setMatrix(ShaderParameter[] params, float x, float y, float width, float height) {
+ Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f);
+ Matrix.scaleM(mTempMatrix, 0, width, height, 1f);
+ Matrix.multiplyMM(mTempMatrix, MATRIX_SIZE, mProjectionMatrix, 0, mTempMatrix, 0);
+ GLES20.glUniformMatrix4fv(params[INDEX_MATRIX].handle, 1, false, mTempMatrix, MATRIX_SIZE);
+ checkError();
+ }
+
+ @Override
+ public void fillRect(float x, float y, float width, float height, int color) {
+ draw(GLES20.GL_TRIANGLE_STRIP, OFFSET_FILL_RECT, COUNT_FILL_VERTEX, x, y, width, height,
+ color, 0f);
+ mCountFillRect++;
+ }
+
+ @Override
+ public void drawTexture(BasicTexture texture, int x, int y, int width, int height) {
+ if (width <= 0 || height <= 0) {
+ return;
+ }
+ copyTextureCoordinates(texture, mTempSourceRect);
+ mTempTargetRect.set(x, y, x + width, y + height);
+ convertCoordinate(mTempSourceRect, mTempTargetRect, texture);
+ drawTextureRect(texture, mTempSourceRect, mTempTargetRect);
+ }
+
+ private static void copyTextureCoordinates(BasicTexture texture, RectF outRect) {
+ int left = 0;
+ int top = 0;
+ int right = texture.getWidth();
+ int bottom = texture.getHeight();
+ if (texture.hasBorder()) {
+ left = 1;
+ top = 1;
+ right -= 1;
+ bottom -= 1;
+ }
+ outRect.set(left, top, right, bottom);
+ }
+
+ @Override
+ public void drawTexture(BasicTexture texture, RectF source, RectF target) {
+ if (target.width() <= 0 || target.height() <= 0) {
+ return;
+ }
+ mTempSourceRect.set(source);
+ mTempTargetRect.set(target);
+
+ convertCoordinate(mTempSourceRect, mTempTargetRect, texture);
+ drawTextureRect(texture, mTempSourceRect, mTempTargetRect);
+ }
+
+ @Override
+ public void drawTexture(BasicTexture texture, float[] textureTransform, int x, int y, int w,
+ int h) {
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+ mTempTargetRect.set(x, y, x + w, y + h);
+ drawTextureRect(texture, textureTransform, mTempTargetRect);
+ }
+
+ private void drawTextureRect(BasicTexture texture, RectF source, RectF target) {
+ setTextureMatrix(source);
+ drawTextureRect(texture, mTempTextureMatrix, target);
+ }
+
+ private void setTextureMatrix(RectF source) {
+ mTempTextureMatrix[0] = source.width();
+ mTempTextureMatrix[5] = source.height();
+ mTempTextureMatrix[12] = source.left;
+ mTempTextureMatrix[13] = source.top;
+ }
+
+ // This function changes the source coordinate to the texture coordinates.
+ // It also clips the source and target coordinates if it is beyond the
+ // bound of the texture.
+ private static void convertCoordinate(RectF source, RectF target, BasicTexture texture) {
+ int width = texture.getWidth();
+ int height = texture.getHeight();
+ int texWidth = texture.getTextureWidth();
+ int texHeight = texture.getTextureHeight();
+ // Convert to texture coordinates
+ source.left /= texWidth;
+ source.right /= texWidth;
+ source.top /= texHeight;
+ source.bottom /= texHeight;
+
+ // Clip if the rendering range is beyond the bound of the texture.
+ float xBound = (float) width / texWidth;
+ if (source.right > xBound) {
+ target.right = target.left + target.width() * (xBound - source.left) / source.width();
+ source.right = xBound;
+ }
+ float yBound = (float) height / texHeight;
+ if (source.bottom > yBound) {
+ target.bottom = target.top + target.height() * (yBound - source.top) / source.height();
+ source.bottom = yBound;
+ }
+ }
+
+ private void drawTextureRect(BasicTexture texture, float[] textureMatrix, RectF target) {
+ ShaderParameter[] params = prepareTexture(texture);
+ setPosition(params, OFFSET_FILL_RECT);
+ GLES20.glUniformMatrix4fv(params[INDEX_TEXTURE_MATRIX].handle, 1, false, textureMatrix, 0);
+ checkError();
+ if (texture.isFlippedVertically()) {
+ save(SAVE_FLAG_MATRIX);
+ translate(0, target.centerY());
+ scale(1, -1, 1);
+ translate(0, -target.centerY());
+ }
+ draw(params, GLES20.GL_TRIANGLE_STRIP, COUNT_FILL_VERTEX, target.left, target.top,
+ target.width(), target.height());
+ if (texture.isFlippedVertically()) {
+ restore();
+ }
+ mCountTextureRect++;
+ }
+
+ private ShaderParameter[] prepareTexture(BasicTexture texture) {
+ ShaderParameter[] params;
+ int program;
+ if (texture.getTarget() == GLES20.GL_TEXTURE_2D) {
+ params = mTextureParameters;
+ program = mTextureProgram;
+ } else {
+ params = mOesTextureParameters;
+ program = mOesTextureProgram;
+ }
+ prepareTexture(texture, program, params);
+ return params;
+ }
+
+ private void prepareTexture(BasicTexture texture, int program, ShaderParameter[] params) {
+ GLES20.glUseProgram(program);
+ checkError();
+ enableBlending(!texture.isOpaque() || getAlpha() < OPAQUE_ALPHA);
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ checkError();
+ texture.onBind(this);
+ GLES20.glBindTexture(texture.getTarget(), texture.getId());
+ checkError();
+ GLES20.glUniform1i(params[INDEX_TEXTURE_SAMPLER].handle, 0);
+ checkError();
+ GLES20.glUniform1f(params[INDEX_ALPHA].handle, getAlpha());
+ checkError();
+ }
+
+ @Override
+ public void drawMesh(BasicTexture texture, int x, int y, int xyBuffer, int uvBuffer,
+ int indexBuffer, int indexCount) {
+ prepareTexture(texture, mMeshProgram, mMeshParameters);
+
+ GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
+ checkError();
+
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, xyBuffer);
+ checkError();
+ int positionHandle = mMeshParameters[INDEX_POSITION].handle;
+ GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
+ VERTEX_STRIDE, 0);
+ checkError();
+
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, uvBuffer);
+ checkError();
+ int texCoordHandle = mMeshParameters[INDEX_TEXTURE_COORD].handle;
+ GLES20.glVertexAttribPointer(texCoordHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
+ false, VERTEX_STRIDE, 0);
+ checkError();
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+ checkError();
+
+ GLES20.glEnableVertexAttribArray(positionHandle);
+ checkError();
+ GLES20.glEnableVertexAttribArray(texCoordHandle);
+ checkError();
+
+ setMatrix(mMeshParameters, x, y, 1, 1);
+ GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, indexCount, GLES20.GL_UNSIGNED_BYTE, 0);
+ checkError();
+
+ GLES20.glDisableVertexAttribArray(positionHandle);
+ checkError();
+ GLES20.glDisableVertexAttribArray(texCoordHandle);
+ checkError();
+ GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
+ checkError();
+ mCountDrawMesh++;
+ }
+
+ @Override
+ public void drawMixed(BasicTexture texture, int toColor, float ratio, int x, int y, int w, int h) {
+ copyTextureCoordinates(texture, mTempSourceRect);
+ mTempTargetRect.set(x, y, x + w, y + h);
+ drawMixed(texture, toColor, ratio, mTempSourceRect, mTempTargetRect);
+ }
+
+ @Override
+ public void drawMixed(BasicTexture texture, int toColor, float ratio, RectF source, RectF target) {
+ if (target.width() <= 0 || target.height() <= 0) {
+ return;
+ }
+ save(SAVE_FLAG_ALPHA);
+
+ float currentAlpha = getAlpha();
+ float cappedRatio = Math.min(1f, Math.max(0f, ratio));
+
+ float textureAlpha = (1f - cappedRatio) * currentAlpha;
+ setAlpha(textureAlpha);
+ drawTexture(texture, source, target);
+
+ float colorAlpha = cappedRatio * currentAlpha;
+ setAlpha(colorAlpha);
+ fillRect(target.left, target.top, target.width(), target.height(), toColor);
+
+ restore();
+ }
+
+ @Override
+ public boolean unloadTexture(BasicTexture texture) {
+ boolean unload = texture.isLoaded();
+ if (unload) {
+ synchronized (mUnboundTextures) {
+ mUnboundTextures.add(texture.getId());
+ }
+ }
+ return unload;
+ }
+
+ @Override
+ public void deleteBuffer(int bufferId) {
+ synchronized (mUnboundTextures) {
+ mDeleteBuffers.add(bufferId);
+ }
+ }
+
+ @Override
+ public void deleteRecycledResources() {
+ synchronized (mUnboundTextures) {
+ IntArray ids = mUnboundTextures;
+ if (mUnboundTextures.size() > 0) {
+ mGLId.glDeleteTextures(null, ids.size(), ids.getInternalArray(), 0);
+ ids.clear();
+ }
+
+ ids = mDeleteBuffers;
+ if (ids.size() > 0) {
+ mGLId.glDeleteBuffers(null, ids.size(), ids.getInternalArray(), 0);
+ ids.clear();
+ }
+ }
+ }
+
+ @Override
+ public void dumpStatisticsAndClear() {
+ String line = String.format("MESH:%d, TEX_RECT:%d, FILL_RECT:%d, LINE:%d", mCountDrawMesh,
+ mCountTextureRect, mCountFillRect, mCountDrawLine);
+ mCountDrawMesh = 0;
+ mCountTextureRect = 0;
+ mCountFillRect = 0;
+ mCountDrawLine = 0;
+ Log.d(TAG, line);
+ }
+
+ @Override
+ public void endRenderTarget() {
+ RawTexture oldTexture = mTargetTextures.remove(mTargetTextures.size() - 1);
+ RawTexture texture = getTargetTexture();
+ setRenderTarget(oldTexture, texture);
+ restore(); // restore matrix and alpha
+ }
+
+ @Override
+ public void beginRenderTarget(RawTexture texture) {
+ save(); // save matrix and alpha and blending
+ RawTexture oldTexture = getTargetTexture();
+ mTargetTextures.add(texture);
+ setRenderTarget(oldTexture, texture);
+ }
+
+ private RawTexture getTargetTexture() {
+ return mTargetTextures.get(mTargetTextures.size() - 1);
+ }
+
+ private void setRenderTarget(BasicTexture oldTexture, RawTexture texture) {
+ if (oldTexture == null && texture != null) {
+ GLES20.glGenFramebuffers(1, mFrameBuffer, 0);
+ checkError();
+ GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffer[0]);
+ checkError();
+ } else if (oldTexture != null && texture == null) {
+ GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+ checkError();
+ GLES20.glDeleteFramebuffers(1, mFrameBuffer, 0);
+ checkError();
+ }
+
+ if (texture == null) {
+ setSize(mScreenWidth, mScreenHeight);
+ } else {
+ setSize(texture.getWidth(), texture.getHeight());
+
+ if (!texture.isLoaded()) {
+ texture.prepare(this);
+ }
+
+ GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
+ texture.getTarget(), texture.getId(), 0);
+ checkError();
+
+ checkFramebufferStatus();
+ }
+ }
+
+ private static void checkFramebufferStatus() {
+ int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
+ if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
+ String msg = "";
+ switch (status) {
+ case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ msg = "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+ break;
+ case GLES20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+ msg = "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+ break;
+ case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ msg = "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+ break;
+ case GLES20.GL_FRAMEBUFFER_UNSUPPORTED:
+ msg = "GL_FRAMEBUFFER_UNSUPPORTED";
+ break;
+ }
+ throw new RuntimeException(msg + ":" + Integer.toHexString(status));
+ }
+ }
+
+ @Override
+ public void setTextureParameters(BasicTexture texture) {
+ int target = texture.getTarget();
+ GLES20.glBindTexture(target, texture.getId());
+ checkError();
+ GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+ GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+ }
+
+ @Override
+ public void initializeTextureSize(BasicTexture texture, int format, int type) {
+ int target = texture.getTarget();
+ GLES20.glBindTexture(target, texture.getId());
+ checkError();
+ int width = texture.getTextureWidth();
+ int height = texture.getTextureHeight();
+ GLES20.glTexImage2D(target, 0, format, width, height, 0, format, type, null);
+ }
+
+ @Override
+ public void initializeTexture(BasicTexture texture, Bitmap bitmap) {
+ int target = texture.getTarget();
+ GLES20.glBindTexture(target, texture.getId());
+ checkError();
+ GLUtils.texImage2D(target, 0, bitmap, 0);
+ }
+
+ @Override
+ public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap,
+ int format, int type) {
+ int target = texture.getTarget();
+ GLES20.glBindTexture(target, texture.getId());
+ checkError();
+ GLUtils.texSubImage2D(target, 0, xOffset, yOffset, bitmap, format, type);
+ }
+
+ @Override
+ public int uploadBuffer(FloatBuffer buf) {
+ return uploadBuffer(buf, FLOAT_SIZE);
+ }
+
+ @Override
+ public int uploadBuffer(ByteBuffer buf) {
+ return uploadBuffer(buf, 1);
+ }
+
+ private int uploadBuffer(Buffer buffer, int elementSize) {
+ mGLId.glGenBuffers(1, mTempIntArray, 0);
+ checkError();
+ int bufferId = mTempIntArray[0];
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId);
+ checkError();
+ GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, buffer.capacity() * elementSize, buffer,
+ GLES20.GL_STATIC_DRAW);
+ checkError();
+ return bufferId;
+ }
+
+ public static void checkError() {
+ int error = GLES20.glGetError();
+ if (error != 0) {
+ Throwable t = new Throwable();
+ Log.e(TAG, "GL error: " + error, t);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void printMatrix(String message, float[] m, int offset) {
+ StringBuilder b = new StringBuilder(message);
+ for (int i = 0; i < MATRIX_SIZE; i++) {
+ b.append(' ');
+ if (i % 4 == 0) {
+ b.append('\n');
+ }
+ b.append(m[offset + i]);
+ }
+ Log.v(TAG, b.toString());
+ }
+
+ @Override
+ public void recoverFromLightCycle() {
+ GLES20.glViewport(0, 0, mWidth, mHeight);
+ GLES20.glDisable(GLES20.GL_DEPTH_TEST);
+ GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
+ checkError();
+ }
+
+ @Override
+ public void getBounds(Rect bounds, int x, int y, int width, int height) {
+ Matrix.translateM(mTempMatrix, 0, mMatrices, mCurrentMatrixIndex, x, y, 0f);
+ Matrix.scaleM(mTempMatrix, 0, width, height, 1f);
+ Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE, mTempMatrix, 0, BOUNDS_COORDINATES, 0);
+ Matrix.multiplyMV(mTempMatrix, MATRIX_SIZE + 4, mTempMatrix, 0, BOUNDS_COORDINATES, 4);
+ bounds.left = Math.round(mTempMatrix[MATRIX_SIZE]);
+ bounds.right = Math.round(mTempMatrix[MATRIX_SIZE + 4]);
+ bounds.top = Math.round(mTempMatrix[MATRIX_SIZE + 1]);
+ bounds.bottom = Math.round(mTempMatrix[MATRIX_SIZE + 5]);
+ bounds.sort();
+ }
+
+ @Override
+ public GLId getGLId() {
+ return mGLId;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java
new file mode 100644
index 0000000..6cd7149
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java
@@ -0,0 +1,42 @@
+package com.android.gallery3d.glrenderer;
+
+import android.opengl.GLES20;
+
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11ExtensionPack;
+
+public class GLES20IdImpl implements GLId {
+ private final int[] mTempIntArray = new int[1];
+
+ @Override
+ public int generateTexture() {
+ GLES20.glGenTextures(1, mTempIntArray, 0);
+ GLES20Canvas.checkError();
+ return mTempIntArray[0];
+ }
+
+ @Override
+ public void glGenBuffers(int n, int[] buffers, int offset) {
+ GLES20.glGenBuffers(n, buffers, offset);
+ GLES20Canvas.checkError();
+ }
+
+ @Override
+ public void glDeleteTextures(GL11 gl, int n, int[] textures, int offset) {
+ GLES20.glDeleteTextures(n, textures, offset);
+ GLES20Canvas.checkError();
+ }
+
+
+ @Override
+ public void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset) {
+ GLES20.glDeleteBuffers(n, buffers, offset);
+ GLES20Canvas.checkError();
+ }
+
+ @Override
+ public void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset) {
+ GLES20.glDeleteFramebuffers(n, buffers, offset);
+ GLES20Canvas.checkError();
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLId.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLId.java
new file mode 100644
index 0000000..3cec558
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLId.java
@@ -0,0 +1,33 @@
+/*
+ * 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 com.android.gallery3d.glrenderer;
+
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11ExtensionPack;
+
+// This mimics corresponding GL functions.
+public interface GLId {
+ public int generateTexture();
+
+ public void glGenBuffers(int n, int[] buffers, int offset);
+
+ public void glDeleteTextures(GL11 gl, int n, int[] textures, int offset);
+
+ public void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset);
+
+ public void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset);
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
new file mode 100644
index 0000000..16b2206
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import junit.framework.Assert;
+
+public class GLPaint {
+ private float mLineWidth = 1f;
+ private int mColor = 0;
+
+ public void setColor(int color) {
+ mColor = color;
+ }
+
+ public int getColor() {
+ return mColor;
+ }
+
+ public void setLineWidth(float width) {
+ Assert.assertTrue(width >= 0);
+ mLineWidth = width;
+ }
+
+ public float getLineWidth() {
+ return mLineWidth;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/RawTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/RawTexture.java
new file mode 100644
index 0000000..93f0fdf
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/RawTexture.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.util.Log;
+
+import javax.microedition.khronos.opengles.GL11;
+
+public class RawTexture extends BasicTexture {
+ private static final String TAG = "RawTexture";
+
+ private final boolean mOpaque;
+ private boolean mIsFlipped;
+
+ public RawTexture(int width, int height, boolean opaque) {
+ mOpaque = opaque;
+ setSize(width, height);
+ }
+
+ @Override
+ public boolean isOpaque() {
+ return mOpaque;
+ }
+
+ @Override
+ public boolean isFlippedVertically() {
+ return mIsFlipped;
+ }
+
+ public void setIsFlippedVertically(boolean isFlipped) {
+ mIsFlipped = isFlipped;
+ }
+
+ protected void prepare(GLCanvas canvas) {
+ GLId glId = canvas.getGLId();
+ mId = glId.generateTexture();
+ canvas.initializeTextureSize(this, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE);
+ canvas.setTextureParameters(this);
+ mState = STATE_LOADED;
+ setAssociatedCanvas(canvas);
+ }
+
+ @Override
+ protected boolean onBind(GLCanvas canvas) {
+ if (isLoaded()) return true;
+ Log.w(TAG, "lost the content due to context change");
+ return false;
+ }
+
+ @Override
+ public void yield() {
+ // we cannot free the texture because we have no backup.
+ }
+
+ @Override
+ protected int getTarget() {
+ return GL11.GL_TEXTURE_2D;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/Texture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/Texture.java
new file mode 100644
index 0000000..3dcae4a
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/Texture.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+
+// Texture is a rectangular image which can be drawn on GLCanvas.
+// The isOpaque() function gives a hint about whether the texture is opaque,
+// so the drawing can be done faster.
+//
+// This is the current texture hierarchy:
+//
+// Texture
+// -- ColorTexture
+// -- FadeInTexture
+// -- BasicTexture
+// -- UploadedTexture
+// -- BitmapTexture
+// -- Tile
+// -- ResourceTexture
+// -- NinePatchTexture
+// -- CanvasTexture
+// -- StringTexture
+//
+public interface Texture {
+ public int getWidth();
+ public int getHeight();
+ public void draw(GLCanvas canvas, int x, int y);
+ public void draw(GLCanvas canvas, int x, int y, int w, int h);
+ public boolean isOpaque();
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
new file mode 100644
index 0000000..f41a979
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.glrenderer;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.opengl.GLUtils;
+
+import junit.framework.Assert;
+
+import java.util.HashMap;
+
+import javax.microedition.khronos.opengles.GL11;
+
+// UploadedTextures use a Bitmap for the content of the texture.
+//
+// Subclasses should implement onGetBitmap() to provide the Bitmap and
+// implement onFreeBitmap(mBitmap) which will be called when the Bitmap
+// is not needed anymore.
+//
+// isContentValid() is meaningful only when the isLoaded() returns true.
+// It means whether the content needs to be updated.
+//
+// The user of this class should call recycle() when the texture is not
+// needed anymore.
+//
+// By default an UploadedTexture is opaque (so it can be drawn faster without
+// blending). The user or subclass can override it using setOpaque().
+public abstract class UploadedTexture extends BasicTexture {
+
+ // To prevent keeping allocation the borders, we store those used borders here.
+ // Since the length will be power of two, it won't use too much memory.
+ private static HashMap<BorderKey, Bitmap> sBorderLines =
+ new HashMap<BorderKey, Bitmap>();
+ private static BorderKey sBorderKey = new BorderKey();
+
+ @SuppressWarnings("unused")
+ private static final String TAG = "Texture";
+ private boolean mContentValid = true;
+
+ // indicate this textures is being uploaded in background
+ private boolean mIsUploading = false;
+ private boolean mOpaque = true;
+ private boolean mThrottled = false;
+ private static int sUploadedCount;
+ private static final int UPLOAD_LIMIT = 100;
+
+ protected Bitmap mBitmap;
+ private int mBorder;
+
+ protected UploadedTexture() {
+ this(false);
+ }
+
+ protected UploadedTexture(boolean hasBorder) {
+ super(null, 0, STATE_UNLOADED);
+ if (hasBorder) {
+ setBorder(true);
+ mBorder = 1;
+ }
+ }
+
+ protected void setIsUploading(boolean uploading) {
+ mIsUploading = uploading;
+ }
+
+ public boolean isUploading() {
+ return mIsUploading;
+ }
+
+ private static class BorderKey implements Cloneable {
+ public boolean vertical;
+ public Config config;
+ public int length;
+
+ @Override
+ public int hashCode() {
+ int x = config.hashCode() ^ length;
+ return vertical ? x : -x;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof BorderKey)) return false;
+ BorderKey o = (BorderKey) object;
+ return vertical == o.vertical
+ && config == o.config && length == o.length;
+ }
+
+ @Override
+ public BorderKey clone() {
+ try {
+ return (BorderKey) super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ protected void setThrottled(boolean throttled) {
+ mThrottled = throttled;
+ }
+
+ private static Bitmap getBorderLine(
+ boolean vertical, Config config, int length) {
+ BorderKey key = sBorderKey;
+ key.vertical = vertical;
+ key.config = config;
+ key.length = length;
+ Bitmap bitmap = sBorderLines.get(key);
+ if (bitmap == null) {
+ bitmap = vertical
+ ? Bitmap.createBitmap(1, length, config)
+ : Bitmap.createBitmap(length, 1, config);
+ sBorderLines.put(key.clone(), bitmap);
+ }
+ return bitmap;
+ }
+
+ private Bitmap getBitmap() {
+ if (mBitmap == null) {
+ mBitmap = onGetBitmap();
+ int w = mBitmap.getWidth() + mBorder * 2;
+ int h = mBitmap.getHeight() + mBorder * 2;
+ if (mWidth == UNSPECIFIED) {
+ setSize(w, h);
+ }
+ }
+ return mBitmap;
+ }
+
+ private void freeBitmap() {
+ Assert.assertTrue(mBitmap != null);
+ onFreeBitmap(mBitmap);
+ mBitmap = null;
+ }
+
+ @Override
+ public int getWidth() {
+ if (mWidth == UNSPECIFIED) getBitmap();
+ return mWidth;
+ }
+
+ @Override
+ public int getHeight() {
+ if (mWidth == UNSPECIFIED) getBitmap();
+ return mHeight;
+ }
+
+ protected abstract Bitmap onGetBitmap();
+
+ protected abstract void onFreeBitmap(Bitmap bitmap);
+
+ protected void invalidateContent() {
+ if (mBitmap != null) freeBitmap();
+ mContentValid = false;
+ mWidth = UNSPECIFIED;
+ mHeight = UNSPECIFIED;
+ }
+
+ /**
+ * Whether the content on GPU is valid.
+ */
+ public boolean isContentValid() {
+ return isLoaded() && mContentValid;
+ }
+
+ /**
+ * Updates the content on GPU's memory.
+ * @param canvas
+ */
+ public void updateContent(GLCanvas canvas) {
+ if (!isLoaded()) {
+ if (mThrottled && ++sUploadedCount > UPLOAD_LIMIT) {
+ return;
+ }
+ uploadToCanvas(canvas);
+ } else if (!mContentValid) {
+ Bitmap bitmap = getBitmap();
+ int format = GLUtils.getInternalFormat(bitmap);
+ int type = GLUtils.getType(bitmap);
+ canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
+ freeBitmap();
+ mContentValid = true;
+ }
+ }
+
+ public static void resetUploadLimit() {
+ sUploadedCount = 0;
+ }
+
+ public static boolean uploadLimitReached() {
+ return sUploadedCount > UPLOAD_LIMIT;
+ }
+
+ private void uploadToCanvas(GLCanvas canvas) {
+
+ Bitmap bitmap = getBitmap();
+ if (bitmap != null) {
+ try {
+ int bWidth = bitmap.getWidth();
+ int bHeight = bitmap.getHeight();
+ int width = bWidth + mBorder * 2;
+ int height = bHeight + mBorder * 2;
+ int texWidth = getTextureWidth();
+ int texHeight = getTextureHeight();
+
+ Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
+
+ // Upload the bitmap to a new texture.
+ mId = canvas.getGLId().generateTexture();
+ canvas.setTextureParameters(this);
+
+ if (bWidth == texWidth && bHeight == texHeight) {
+ canvas.initializeTexture(this, bitmap);
+ } else {
+ int format = GLUtils.getInternalFormat(bitmap);
+ int type = GLUtils.getType(bitmap);
+ Config config = bitmap.getConfig();
+
+ canvas.initializeTextureSize(this, format, type);
+ canvas.texSubImage2D(this, mBorder, mBorder, bitmap, format, type);
+
+ if (mBorder > 0) {
+ // Left border
+ Bitmap line = getBorderLine(true, config, texHeight);
+ canvas.texSubImage2D(this, 0, 0, line, format, type);
+
+ // Top border
+ line = getBorderLine(false, config, texWidth);
+ canvas.texSubImage2D(this, 0, 0, line, format, type);
+ }
+
+ // Right border
+ if (mBorder + bWidth < texWidth) {
+ Bitmap line = getBorderLine(true, config, texHeight);
+ canvas.texSubImage2D(this, mBorder + bWidth, 0, line, format, type);
+ }
+
+ // Bottom border
+ if (mBorder + bHeight < texHeight) {
+ Bitmap line = getBorderLine(false, config, texWidth);
+ canvas.texSubImage2D(this, 0, mBorder + bHeight, line, format, type);
+ }
+ }
+ } finally {
+ freeBitmap();
+ }
+ // Update texture state.
+ setAssociatedCanvas(canvas);
+ mState = STATE_LOADED;
+ mContentValid = true;
+ } else {
+ mState = STATE_ERROR;
+ throw new RuntimeException("Texture load fail, no bitmap");
+ }
+ }
+
+ @Override
+ protected boolean onBind(GLCanvas canvas) {
+ updateContent(canvas);
+ return isContentValid();
+ }
+
+ @Override
+ protected int getTarget() {
+ return GL11.GL_TEXTURE_2D;
+ }
+
+ public void setOpaque(boolean isOpaque) {
+ mOpaque = isOpaque;
+ }
+
+ @Override
+ public boolean isOpaque() {
+ return mOpaque;
+ }
+
+ @Override
+ public void recycle() {
+ super.recycle();
+ if (mBitmap != null) freeBitmap();
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/util/IntArray.java b/packages/WallpaperCropper/src/com/android/gallery3d/util/IntArray.java
new file mode 100644
index 0000000..2c4dc2c
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/util/IntArray.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.util;
+
+public class IntArray {
+ private static final int INIT_CAPACITY = 8;
+
+ private int mData[] = new int[INIT_CAPACITY];
+ private int mSize = 0;
+
+ public void add(int value) {
+ if (mData.length == mSize) {
+ int temp[] = new int[mSize + mSize];
+ System.arraycopy(mData, 0, temp, 0, mSize);
+ mData = temp;
+ }
+ mData[mSize++] = value;
+ }
+
+ public int removeLast() {
+ mSize--;
+ return mData[mSize];
+ }
+
+ public int size() {
+ return mSize;
+ }
+
+ // For testing only
+ public int[] toArray(int[] result) {
+ if (result == null || result.length < mSize) {
+ result = new int[mSize];
+ }
+ System.arraycopy(mData, 0, result, 0, mSize);
+ return result;
+ }
+
+ public int[] getInternalArray() {
+ return mData;
+ }
+
+ public void clear() {
+ mSize = 0;
+ if (mData.length != INIT_CAPACITY) mData = new int[INIT_CAPACITY];
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
new file mode 100644
index 0000000..5f64018
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
@@ -0,0 +1,260 @@
+/*
+ * 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.photos;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.util.Log;
+
+import com.android.gallery3d.common.BitmapUtils;
+import com.android.gallery3d.glrenderer.BasicTexture;
+import com.android.gallery3d.glrenderer.BitmapTexture;
+import com.android.photos.views.TiledImageRenderer;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A {@link com.android.photos.views.TiledImageRenderer.TileSource} using
+ * {@link BitmapRegionDecoder} to wrap a local file
+ */
+@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
+public class BitmapRegionTileSource implements TiledImageRenderer.TileSource {
+
+ private static final String TAG = "BitmapRegionTileSource";
+
+ private static final boolean REUSE_BITMAP =
+ Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN;
+ private static final int GL_SIZE_LIMIT = 2048;
+ // This must be no larger than half the size of the GL_SIZE_LIMIT
+ // due to decodePreview being allowed to be up to 2x the size of the target
+ private static final int MAX_PREVIEW_SIZE = 1024;
+
+ BitmapRegionDecoder mDecoder;
+ int mWidth;
+ int mHeight;
+ int mTileSize;
+ private BasicTexture mPreview;
+ private final int mRotation;
+
+ // For use only by getTile
+ private Rect mWantRegion = new Rect();
+ private Rect mOverlapRegion = new Rect();
+ private BitmapFactory.Options mOptions;
+ private Canvas mCanvas;
+
+ public BitmapRegionTileSource(Context context, String path, int previewSize, int rotation) {
+ this(null, context, path, null, 0, previewSize, rotation);
+ }
+
+ public BitmapRegionTileSource(Context context, Uri uri, int previewSize, int rotation) {
+ this(null, context, null, uri, 0, previewSize, rotation);
+ }
+
+ public BitmapRegionTileSource(Resources res,
+ Context context, int resId, int previewSize, int rotation) {
+ this(res, context, null, null, resId, previewSize, rotation);
+ }
+
+ private BitmapRegionTileSource(Resources res,
+ Context context, String path, Uri uri, int resId, int previewSize, int rotation) {
+ mTileSize = TiledImageRenderer.suggestedTileSize(context);
+ mRotation = rotation;
+ try {
+ if (path != null) {
+ mDecoder = BitmapRegionDecoder.newInstance(path, true);
+ } else if (uri != null) {
+ InputStream is = context.getContentResolver().openInputStream(uri);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ mDecoder = BitmapRegionDecoder.newInstance(bis, true);
+ } else {
+ InputStream is = res.openRawResource(resId);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ mDecoder = BitmapRegionDecoder.newInstance(bis, true);
+ }
+ mWidth = mDecoder.getWidth();
+ mHeight = mDecoder.getHeight();
+ } catch (IOException e) {
+ Log.w("BitmapRegionTileSource", "ctor failed", e);
+ }
+ mOptions = new BitmapFactory.Options();
+ mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ mOptions.inPreferQualityOverSpeed = true;
+ mOptions.inTempStorage = new byte[16 * 1024];
+ if (previewSize != 0) {
+ previewSize = Math.min(previewSize, MAX_PREVIEW_SIZE);
+ // Although this is the same size as the Bitmap that is likely already
+ // loaded, the lifecycle is different and interactions are on a different
+ // thread. Thus to simplify, this source will decode its own bitmap.
+ Bitmap preview = decodePreview(res, context, path, uri, resId, previewSize);
+ if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) {
+ mPreview = new BitmapTexture(preview);
+ } else {
+ Log.w(TAG, String.format(
+ "Failed to create preview of apropriate size! "
+ + " in: %dx%d, out: %dx%d",
+ mWidth, mHeight,
+ preview.getWidth(), preview.getHeight()));
+ }
+ }
+ }
+
+ @Override
+ public int getTileSize() {
+ return mTileSize;
+ }
+
+ @Override
+ public int getImageWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getImageHeight() {
+ return mHeight;
+ }
+
+ @Override
+ public BasicTexture getPreview() {
+ return mPreview;
+ }
+
+ @Override
+ public int getRotation() {
+ return mRotation;
+ }
+
+ @Override
+ public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
+ int tileSize = getTileSize();
+ if (!REUSE_BITMAP) {
+ return getTileWithoutReusingBitmap(level, x, y, tileSize);
+ }
+
+ int t = tileSize << level;
+ mWantRegion.set(x, y, x + t, y + t);
+
+ if (bitmap == null) {
+ bitmap = Bitmap.createBitmap(tileSize, tileSize, Bitmap.Config.ARGB_8888);
+ }
+
+ mOptions.inSampleSize = (1 << level);
+ mOptions.inBitmap = bitmap;
+
+ try {
+ bitmap = mDecoder.decodeRegion(mWantRegion, mOptions);
+ } finally {
+ if (mOptions.inBitmap != bitmap && mOptions.inBitmap != null) {
+ mOptions.inBitmap = null;
+ }
+ }
+
+ if (bitmap == null) {
+ Log.w("BitmapRegionTileSource", "fail in decoding region");
+ }
+ return bitmap;
+ }
+
+ private Bitmap getTileWithoutReusingBitmap(
+ int level, int x, int y, int tileSize) {
+
+ int t = tileSize << level;
+ mWantRegion.set(x, y, x + t, y + t);
+
+ mOverlapRegion.set(0, 0, mWidth, mHeight);
+
+ mOptions.inSampleSize = (1 << level);
+ Bitmap bitmap = mDecoder.decodeRegion(mOverlapRegion, mOptions);
+
+ if (bitmap == null) {
+ Log.w(TAG, "fail in decoding region");
+ }
+
+ if (mWantRegion.equals(mOverlapRegion)) {
+ return bitmap;
+ }
+
+ Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888);
+ if (mCanvas == null) {
+ mCanvas = new Canvas();
+ }
+ mCanvas.setBitmap(result);
+ mCanvas.drawBitmap(bitmap,
+ (mOverlapRegion.left - mWantRegion.left) >> level,
+ (mOverlapRegion.top - mWantRegion.top) >> level, null);
+ mCanvas.setBitmap(null);
+ return result;
+ }
+
+ /**
+ * Note that the returned bitmap may have a long edge that's longer
+ * than the targetSize, but it will always be less than 2x the targetSize
+ */
+ private Bitmap decodePreview(
+ Resources res, Context context, String file, Uri uri, int resId, int targetSize) {
+ float scale = (float) targetSize / Math.max(mWidth, mHeight);
+ mOptions.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
+ mOptions.inJustDecodeBounds = false;
+
+ Bitmap result = null;
+ if (file != null) {
+ result = BitmapFactory.decodeFile(file, mOptions);
+ } else if (uri != null) {
+ try {
+ InputStream is = context.getContentResolver().openInputStream(uri);
+ BufferedInputStream bis = new BufferedInputStream(is);
+ result = BitmapFactory.decodeStream(bis, null, mOptions);
+ } catch (IOException e) {
+ Log.w("BitmapRegionTileSource", "getting preview failed", e);
+ }
+ } else {
+ result = BitmapFactory.decodeResource(res, resId, mOptions);
+ }
+ if (result == null) {
+ return null;
+ }
+
+ // We need to resize down if the decoder does not support inSampleSize
+ // or didn't support the specified inSampleSize (some decoders only do powers of 2)
+ scale = (float) targetSize / (float) (Math.max(result.getWidth(), result.getHeight()));
+
+ if (scale <= 0.5) {
+ result = BitmapUtils.resizeBitmapByScale(result, scale, true);
+ }
+ return ensureGLCompatibleBitmap(result);
+ }
+
+ private static Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) {
+ if (bitmap == null || bitmap.getConfig() != null) {
+ return bitmap;
+ }
+ Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false);
+ bitmap.recycle();
+ return newBitmap;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/BlockingGLTextureView.java b/packages/WallpaperCropper/src/com/android/photos/views/BlockingGLTextureView.java
new file mode 100644
index 0000000..8a05051
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/views/BlockingGLTextureView.java
@@ -0,0 +1,438 @@
+/*
+ * 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.photos.views;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLSurfaceView.Renderer;
+import android.opengl.GLUtils;
+import android.util.Log;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * A TextureView that supports blocking rendering for synchronous drawing
+ */
+public class BlockingGLTextureView extends TextureView
+ implements SurfaceTextureListener {
+
+ private RenderThread mRenderThread;
+
+ public BlockingGLTextureView(Context context) {
+ super(context);
+ setSurfaceTextureListener(this);
+ }
+
+ public void setRenderer(Renderer renderer) {
+ if (mRenderThread != null) {
+ throw new IllegalArgumentException("Renderer already set");
+ }
+ mRenderThread = new RenderThread(renderer);
+ }
+
+ public void render() {
+ mRenderThread.render();
+ }
+
+ public void destroy() {
+ if (mRenderThread != null) {
+ mRenderThread.finish();
+ mRenderThread = null;
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
+ int height) {
+ mRenderThread.setSurface(surface);
+ mRenderThread.setSize(width, height);
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
+ int height) {
+ mRenderThread.setSize(width, height);
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ if (mRenderThread != null) {
+ mRenderThread.setSurface(null);
+ }
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ } catch (Throwable t) {
+ // Ignore
+ }
+ super.finalize();
+ }
+
+ /**
+ * An EGL helper class.
+ */
+
+ private static class EglHelper {
+ private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ private static final int EGL_OPENGL_ES2_BIT = 4;
+
+ EGL10 mEgl;
+ EGLDisplay mEglDisplay;
+ EGLSurface mEglSurface;
+ EGLConfig mEglConfig;
+ EGLContext mEglContext;
+
+ private EGLConfig chooseEglConfig() {
+ int[] configsCount = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] configSpec = getConfig();
+ if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+ throw new IllegalArgumentException("eglChooseConfig failed " +
+ GLUtils.getEGLErrorString(mEgl.eglGetError()));
+ } else if (configsCount[0] > 0) {
+ return configs[0];
+ }
+ return null;
+ }
+
+ private static int[] getConfig() {
+ return new int[] {
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_ALPHA_SIZE, 8,
+ EGL10.EGL_DEPTH_SIZE, 0,
+ EGL10.EGL_STENCIL_SIZE, 0,
+ EGL10.EGL_NONE
+ };
+ }
+
+ EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+ int[] attribList = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attribList);
+ }
+
+ /**
+ * Initialize EGL for a given configuration spec.
+ */
+ public void start() {
+ /*
+ * Get an EGL instance
+ */
+ mEgl = (EGL10) EGLContext.getEGL();
+
+ /*
+ * Get to the default display.
+ */
+ mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
+ if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+ throw new RuntimeException("eglGetDisplay failed");
+ }
+
+ /*
+ * We can now initialize EGL for that display
+ */
+ int[] version = new int[2];
+ if (!mEgl.eglInitialize(mEglDisplay, version)) {
+ throw new RuntimeException("eglInitialize failed");
+ }
+ mEglConfig = chooseEglConfig();
+
+ /*
+ * Create an EGL context. We want to do this as rarely as we can, because an
+ * EGL context is a somewhat heavy object.
+ */
+ mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+ if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
+ mEglContext = null;
+ throwEglException("createContext");
+ }
+
+ mEglSurface = null;
+ }
+
+ /**
+ * Create an egl surface for the current SurfaceTexture surface. If a surface
+ * already exists, destroy it before creating the new surface.
+ *
+ * @return true if the surface was created successfully.
+ */
+ public boolean createSurface(SurfaceTexture surface) {
+ /*
+ * Check preconditions.
+ */
+ if (mEgl == null) {
+ throw new RuntimeException("egl not initialized");
+ }
+ if (mEglDisplay == null) {
+ throw new RuntimeException("eglDisplay not initialized");
+ }
+ if (mEglConfig == null) {
+ throw new RuntimeException("mEglConfig not initialized");
+ }
+
+ /*
+ * The window size has changed, so we need to create a new
+ * surface.
+ */
+ destroySurfaceImp();
+
+ /*
+ * Create an EGL surface we can render into.
+ */
+ if (surface != null) {
+ mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null);
+ } else {
+ mEglSurface = null;
+ }
+
+ if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+ int error = mEgl.eglGetError();
+ if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+ Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+ }
+ return false;
+ }
+
+ /*
+ * Before we can issue GL commands, we need to make sure
+ * the context is current and bound to a surface.
+ */
+ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ /*
+ * Could not make the context current, probably because the underlying
+ * SurfaceView surface has been destroyed.
+ */
+ logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Create a GL object for the current EGL context.
+ */
+ public GL10 createGL() {
+ return (GL10) mEglContext.getGL();
+ }
+
+ /**
+ * Display the current render surface.
+ * @return the EGL error code from eglSwapBuffers.
+ */
+ public int swap() {
+ if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+ return mEgl.eglGetError();
+ }
+ return EGL10.EGL_SUCCESS;
+ }
+
+ public void destroySurface() {
+ destroySurfaceImp();
+ }
+
+ private void destroySurfaceImp() {
+ if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
+ mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_CONTEXT);
+ mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+ mEglSurface = null;
+ }
+ }
+
+ public void finish() {
+ if (mEglContext != null) {
+ mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+ mEglContext = null;
+ }
+ if (mEglDisplay != null) {
+ mEgl.eglTerminate(mEglDisplay);
+ mEglDisplay = null;
+ }
+ }
+
+ private void throwEglException(String function) {
+ throwEglException(function, mEgl.eglGetError());
+ }
+
+ public static void throwEglException(String function, int error) {
+ String message = formatEglError(function, error);
+ throw new RuntimeException(message);
+ }
+
+ public static void logEglErrorAsWarning(String tag, String function, int error) {
+ Log.w(tag, formatEglError(function, error));
+ }
+
+ public static String formatEglError(String function, int error) {
+ return function + " failed: " + error;
+ }
+
+ }
+
+ private static class RenderThread extends Thread {
+ private static final int INVALID = -1;
+ private static final int RENDER = 1;
+ private static final int CHANGE_SURFACE = 2;
+ private static final int RESIZE_SURFACE = 3;
+ private static final int FINISH = 4;
+
+ private EglHelper mEglHelper = new EglHelper();
+
+ private Object mLock = new Object();
+ private int mExecMsgId = INVALID;
+ private SurfaceTexture mSurface;
+ private Renderer mRenderer;
+ private int mWidth, mHeight;
+
+ private boolean mFinished = false;
+ private GL10 mGL;
+
+ public RenderThread(Renderer renderer) {
+ super("RenderThread");
+ mRenderer = renderer;
+ start();
+ }
+
+ private void checkRenderer() {
+ if (mRenderer == null) {
+ throw new IllegalArgumentException("Renderer is null!");
+ }
+ }
+
+ private void checkSurface() {
+ if (mSurface == null) {
+ throw new IllegalArgumentException("surface is null!");
+ }
+ }
+
+ public void setSurface(SurfaceTexture surface) {
+ // If the surface is null we're being torn down, don't need a
+ // renderer then
+ if (surface != null) {
+ checkRenderer();
+ }
+ mSurface = surface;
+ exec(CHANGE_SURFACE);
+ }
+
+ public void setSize(int width, int height) {
+ checkRenderer();
+ checkSurface();
+ mWidth = width;
+ mHeight = height;
+ exec(RESIZE_SURFACE);
+ }
+
+ public void render() {
+ checkRenderer();
+ if (mSurface != null) {
+ exec(RENDER);
+ mSurface.updateTexImage();
+ }
+ }
+
+ public void finish() {
+ mSurface = null;
+ exec(FINISH);
+ try {
+ join();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+
+ private void exec(int msgid) {
+ synchronized (mLock) {
+ if (mExecMsgId != INVALID) {
+ throw new IllegalArgumentException(
+ "Message already set - multithreaded access?");
+ }
+ mExecMsgId = msgid;
+ mLock.notify();
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+ private void handleMessageLocked(int what) {
+ switch (what) {
+ case CHANGE_SURFACE:
+ if (mEglHelper.createSurface(mSurface)) {
+ mGL = mEglHelper.createGL();
+ mRenderer.onSurfaceCreated(mGL, mEglHelper.mEglConfig);
+ }
+ break;
+ case RESIZE_SURFACE:
+ mRenderer.onSurfaceChanged(mGL, mWidth, mHeight);
+ break;
+ case RENDER:
+ mRenderer.onDrawFrame(mGL);
+ mEglHelper.swap();
+ break;
+ case FINISH:
+ mEglHelper.destroySurface();
+ mEglHelper.finish();
+ mFinished = true;
+ break;
+ }
+ }
+
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ mEglHelper.start();
+ while (!mFinished) {
+ while (mExecMsgId == INVALID) {
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ handleMessageLocked(mExecMsgId);
+ mExecMsgId = INVALID;
+ mLock.notify();
+ }
+ mExecMsgId = FINISH;
+ }
+ }
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
new file mode 100644
index 0000000..c4e493b
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
@@ -0,0 +1,825 @@
+/*
+ * 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.photos.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.support.v4.util.LongSparseArray;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Pools.Pool;
+import android.util.Pools.SynchronizedPool;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.glrenderer.BasicTexture;
+import com.android.gallery3d.glrenderer.GLCanvas;
+import com.android.gallery3d.glrenderer.UploadedTexture;
+
+/**
+ * Handles laying out, decoding, and drawing of tiles in GL
+ */
+public class TiledImageRenderer {
+ public static final int SIZE_UNKNOWN = -1;
+
+ private static final String TAG = "TiledImageRenderer";
+ private static final int UPLOAD_LIMIT = 1;
+
+ /*
+ * This is the tile state in the CPU side.
+ * Life of a Tile:
+ * ACTIVATED (initial state)
+ * --> IN_QUEUE - by queueForDecode()
+ * --> RECYCLED - by recycleTile()
+ * IN_QUEUE --> DECODING - by decodeTile()
+ * --> RECYCLED - by recycleTile)
+ * DECODING --> RECYCLING - by recycleTile()
+ * --> DECODED - by decodeTile()
+ * --> DECODE_FAIL - by decodeTile()
+ * RECYCLING --> RECYCLED - by decodeTile()
+ * DECODED --> ACTIVATED - (after the decoded bitmap is uploaded)
+ * DECODED --> RECYCLED - by recycleTile()
+ * DECODE_FAIL -> RECYCLED - by recycleTile()
+ * RECYCLED --> ACTIVATED - by obtainTile()
+ */
+ private static final int STATE_ACTIVATED = 0x01;
+ private static final int STATE_IN_QUEUE = 0x02;
+ private static final int STATE_DECODING = 0x04;
+ private static final int STATE_DECODED = 0x08;
+ private static final int STATE_DECODE_FAIL = 0x10;
+ private static final int STATE_RECYCLING = 0x20;
+ private static final int STATE_RECYCLED = 0x40;
+
+ private static Pool<Bitmap> sTilePool = new SynchronizedPool<Bitmap>(64);
+
+ // TILE_SIZE must be 2^N
+ private int mTileSize;
+
+ private TileSource mModel;
+ private BasicTexture mPreview;
+ protected int mLevelCount; // cache the value of mScaledBitmaps.length
+
+ // The mLevel variable indicates which level of bitmap we should use.
+ // Level 0 means the original full-sized bitmap, and a larger value means
+ // a smaller scaled bitmap (The width and height of each scaled bitmap is
+ // half size of the previous one). If the value is in [0, mLevelCount), we
+ // use the bitmap in mScaledBitmaps[mLevel] for display, otherwise the value
+ // is mLevelCount
+ private int mLevel = 0;
+
+ private int mOffsetX;
+ private int mOffsetY;
+
+ private int mUploadQuota;
+ private boolean mRenderComplete;
+
+ private final RectF mSourceRect = new RectF();
+ private final RectF mTargetRect = new RectF();
+
+ private final LongSparseArray<Tile> mActiveTiles = new LongSparseArray<Tile>();
+
+ // The following three queue are guarded by mQueueLock
+ private final Object mQueueLock = new Object();
+ private final TileQueue mRecycledQueue = new TileQueue();
+ private final TileQueue mUploadQueue = new TileQueue();
+ private final TileQueue mDecodeQueue = new TileQueue();
+
+ // The width and height of the full-sized bitmap
+ protected int mImageWidth = SIZE_UNKNOWN;
+ protected int mImageHeight = SIZE_UNKNOWN;
+
+ protected int mCenterX;
+ protected int mCenterY;
+ protected float mScale;
+ protected int mRotation;
+
+ private boolean mLayoutTiles;
+
+ // Temp variables to avoid memory allocation
+ private final Rect mTileRange = new Rect();
+ private final Rect mActiveRange[] = {new Rect(), new Rect()};
+
+ private TileDecoder mTileDecoder;
+ private boolean mBackgroundTileUploaded;
+
+ private int mViewWidth, mViewHeight;
+ private View mParent;
+
+ /**
+ * Interface for providing tiles to a {@link TiledImageRenderer}
+ */
+ public static interface TileSource {
+
+ /**
+ * If the source does not care about the tile size, it should use
+ * {@link TiledImageRenderer#suggestedTileSize(Context)}
+ */
+ public int getTileSize();
+ public int getImageWidth();
+ public int getImageHeight();
+ public int getRotation();
+
+ /**
+ * Return a Preview image if available. This will be used as the base layer
+ * if higher res tiles are not yet available
+ */
+ public BasicTexture getPreview();
+
+ /**
+ * The tile returned by this method can be specified this way: Assuming
+ * the image size is (width, height), first take the intersection of (0,
+ * 0) - (width, height) and (x, y) - (x + tileSize, y + tileSize). If
+ * in extending the region, we found some part of the region is outside
+ * the image, those pixels are filled with black.
+ *
+ * If level > 0, it does the same operation on a down-scaled version of
+ * the original image (down-scaled by a factor of 2^level), but (x, y)
+ * still refers to the coordinate on the original image.
+ *
+ * The method would be called by the decoder thread.
+ */
+ public Bitmap getTile(int level, int x, int y, Bitmap reuse);
+ }
+
+ public static int suggestedTileSize(Context context) {
+ return isHighResolution(context) ? 512 : 256;
+ }
+
+ private static boolean isHighResolution(Context context) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager wm = (WindowManager)
+ context.getSystemService(Context.WINDOW_SERVICE);
+ wm.getDefaultDisplay().getMetrics(metrics);
+ return metrics.heightPixels > 2048 || metrics.widthPixels > 2048;
+ }
+
+ public TiledImageRenderer(View parent) {
+ mParent = parent;
+ mTileDecoder = new TileDecoder();
+ mTileDecoder.start();
+ }
+
+ public int getViewWidth() {
+ return mViewWidth;
+ }
+
+ public int getViewHeight() {
+ return mViewHeight;
+ }
+
+ private void invalidate() {
+ mParent.postInvalidate();
+ }
+
+ public void setModel(TileSource model, int rotation) {
+ if (mModel != model) {
+ mModel = model;
+ notifyModelInvalidated();
+ }
+ if (mRotation != rotation) {
+ mRotation = rotation;
+ mLayoutTiles = true;
+ }
+ }
+
+ private void calculateLevelCount() {
+ if (mPreview != null) {
+ mLevelCount = Math.max(0, Utils.ceilLog2(
+ mImageWidth / (float) mPreview.getWidth()));
+ } else {
+ int levels = 1;
+ int maxDim = Math.max(mImageWidth, mImageHeight);
+ int t = mTileSize;
+ while (t < maxDim) {
+ t <<= 1;
+ levels++;
+ }
+ mLevelCount = levels;
+ }
+ }
+
+ public void notifyModelInvalidated() {
+ invalidateTiles();
+ if (mModel == null) {
+ mImageWidth = 0;
+ mImageHeight = 0;
+ mLevelCount = 0;
+ mPreview = null;
+ } else {
+ mImageWidth = mModel.getImageWidth();
+ mImageHeight = mModel.getImageHeight();
+ mPreview = mModel.getPreview();
+ mTileSize = mModel.getTileSize();
+ calculateLevelCount();
+ }
+ mLayoutTiles = true;
+ }
+
+ public void setViewSize(int width, int height) {
+ mViewWidth = width;
+ mViewHeight = height;
+ }
+
+ public void setPosition(int centerX, int centerY, float scale) {
+ if (mCenterX == centerX && mCenterY == centerY
+ && mScale == scale) {
+ return;
+ }
+ mCenterX = centerX;
+ mCenterY = centerY;
+ mScale = scale;
+ mLayoutTiles = true;
+ }
+
+ // Prepare the tiles we want to use for display.
+ //
+ // 1. Decide the tile level we want to use for display.
+ // 2. Decide the tile levels we want to keep as texture (in addition to
+ // the one we use for display).
+ // 3. Recycle unused tiles.
+ // 4. Activate the tiles we want.
+ private void layoutTiles() {
+ if (mViewWidth == 0 || mViewHeight == 0 || !mLayoutTiles) {
+ return;
+ }
+ mLayoutTiles = false;
+
+ // The tile levels we want to keep as texture is in the range
+ // [fromLevel, endLevel).
+ int fromLevel;
+ int endLevel;
+
+ // We want to use a texture larger than or equal to the display size.
+ mLevel = Utils.clamp(Utils.floorLog2(1f / mScale), 0, mLevelCount);
+
+ // We want to keep one more tile level as texture in addition to what
+ // we use for display. So it can be faster when the scale moves to the
+ // next level. We choose the level closest to the current scale.
+ if (mLevel != mLevelCount) {
+ Rect range = mTileRange;
+ getRange(range, mCenterX, mCenterY, mLevel, mScale, mRotation);
+ mOffsetX = Math.round(mViewWidth / 2f + (range.left - mCenterX) * mScale);
+ mOffsetY = Math.round(mViewHeight / 2f + (range.top - mCenterY) * mScale);
+ fromLevel = mScale * (1 << mLevel) > 0.75f ? mLevel - 1 : mLevel;
+ } else {
+ // Activate the tiles of the smallest two levels.
+ fromLevel = mLevel - 2;
+ mOffsetX = Math.round(mViewWidth / 2f - mCenterX * mScale);
+ mOffsetY = Math.round(mViewHeight / 2f - mCenterY * mScale);
+ }
+
+ fromLevel = Math.max(0, Math.min(fromLevel, mLevelCount - 2));
+ endLevel = Math.min(fromLevel + 2, mLevelCount);
+
+ Rect range[] = mActiveRange;
+ for (int i = fromLevel; i < endLevel; ++i) {
+ getRange(range[i - fromLevel], mCenterX, mCenterY, i, mRotation);
+ }
+
+ // If rotation is transient, don't update the tile.
+ if (mRotation % 90 != 0) {
+ return;
+ }
+
+ synchronized (mQueueLock) {
+ mDecodeQueue.clean();
+ mUploadQueue.clean();
+ mBackgroundTileUploaded = false;
+
+ // Recycle unused tiles: if the level of the active tile is outside the
+ // range [fromLevel, endLevel) or not in the visible range.
+ int n = mActiveTiles.size();
+ for (int i = 0; i < n; i++) {
+ Tile tile = mActiveTiles.valueAt(i);
+ int level = tile.mTileLevel;
+ if (level < fromLevel || level >= endLevel
+ || !range[level - fromLevel].contains(tile.mX, tile.mY)) {
+ mActiveTiles.removeAt(i);
+ i--;
+ n--;
+ recycleTile(tile);
+ }
+ }
+ }
+
+ for (int i = fromLevel; i < endLevel; ++i) {
+ int size = mTileSize << i;
+ Rect r = range[i - fromLevel];
+ for (int y = r.top, bottom = r.bottom; y < bottom; y += size) {
+ for (int x = r.left, right = r.right; x < right; x += size) {
+ activateTile(x, y, i);
+ }
+ }
+ }
+ invalidate();
+ }
+
+ private void invalidateTiles() {
+ synchronized (mQueueLock) {
+ mDecodeQueue.clean();
+ mUploadQueue.clean();
+
+ // TODO(xx): disable decoder
+ int n = mActiveTiles.size();
+ for (int i = 0; i < n; i++) {
+ Tile tile = mActiveTiles.valueAt(i);
+ recycleTile(tile);
+ }
+ mActiveTiles.clear();
+ }
+ }
+
+ private void getRange(Rect out, int cX, int cY, int level, int rotation) {
+ getRange(out, cX, cY, level, 1f / (1 << (level + 1)), rotation);
+ }
+
+ // If the bitmap is scaled by the given factor "scale", return the
+ // rectangle containing visible range. The left-top coordinate returned is
+ // aligned to the tile boundary.
+ //
+ // (cX, cY) is the point on the original bitmap which will be put in the
+ // center of the ImageViewer.
+ private void getRange(Rect out,
+ int cX, int cY, int level, float scale, int rotation) {
+
+ double radians = Math.toRadians(-rotation);
+ double w = mViewWidth;
+ double h = mViewHeight;
+
+ double cos = Math.cos(radians);
+ double sin = Math.sin(radians);
+ int width = (int) Math.ceil(Math.max(
+ Math.abs(cos * w - sin * h), Math.abs(cos * w + sin * h)));
+ int height = (int) Math.ceil(Math.max(
+ Math.abs(sin * w + cos * h), Math.abs(sin * w - cos * h)));
+
+ int left = (int) Math.floor(cX - width / (2f * scale));
+ int top = (int) Math.floor(cY - height / (2f * scale));
+ int right = (int) Math.ceil(left + width / scale);
+ int bottom = (int) Math.ceil(top + height / scale);
+
+ // align the rectangle to tile boundary
+ int size = mTileSize << level;
+ left = Math.max(0, size * (left / size));
+ top = Math.max(0, size * (top / size));
+ right = Math.min(mImageWidth, right);
+ bottom = Math.min(mImageHeight, bottom);
+
+ out.set(left, top, right, bottom);
+ }
+
+ public void freeTextures() {
+ mLayoutTiles = true;
+
+ mTileDecoder.finishAndWait();
+ synchronized (mQueueLock) {
+ mUploadQueue.clean();
+ mDecodeQueue.clean();
+ Tile tile = mRecycledQueue.pop();
+ while (tile != null) {
+ tile.recycle();
+ tile = mRecycledQueue.pop();
+ }
+ }
+
+ int n = mActiveTiles.size();
+ for (int i = 0; i < n; i++) {
+ Tile texture = mActiveTiles.valueAt(i);
+ texture.recycle();
+ }
+ mActiveTiles.clear();
+ mTileRange.set(0, 0, 0, 0);
+
+ while (sTilePool.acquire() != null) {}
+ }
+
+ public boolean draw(GLCanvas canvas) {
+ layoutTiles();
+ uploadTiles(canvas);
+
+ mUploadQuota = UPLOAD_LIMIT;
+ mRenderComplete = true;
+
+ int level = mLevel;
+ int rotation = mRotation;
+ int flags = 0;
+ if (rotation != 0) {
+ flags |= GLCanvas.SAVE_FLAG_MATRIX;
+ }
+
+ if (flags != 0) {
+ canvas.save(flags);
+ if (rotation != 0) {
+ int centerX = mViewWidth / 2, centerY = mViewHeight / 2;
+ canvas.translate(centerX, centerY);
+ canvas.rotate(rotation, 0, 0, 1);
+ canvas.translate(-centerX, -centerY);
+ }
+ }
+ try {
+ if (level != mLevelCount) {
+ int size = (mTileSize << level);
+ float length = size * mScale;
+ Rect r = mTileRange;
+
+ for (int ty = r.top, i = 0; ty < r.bottom; ty += size, i++) {
+ float y = mOffsetY + i * length;
+ for (int tx = r.left, j = 0; tx < r.right; tx += size, j++) {
+ float x = mOffsetX + j * length;
+ drawTile(canvas, tx, ty, level, x, y, length);
+ }
+ }
+ } else if (mPreview != null) {
+ mPreview.draw(canvas, mOffsetX, mOffsetY,
+ Math.round(mImageWidth * mScale),
+ Math.round(mImageHeight * mScale));
+ }
+ } finally {
+ if (flags != 0) {
+ canvas.restore();
+ }
+ }
+
+ if (mRenderComplete) {
+ if (!mBackgroundTileUploaded) {
+ uploadBackgroundTiles(canvas);
+ }
+ } else {
+ invalidate();
+ }
+ return mRenderComplete || mPreview != null;
+ }
+
+ private void uploadBackgroundTiles(GLCanvas canvas) {
+ mBackgroundTileUploaded = true;
+ int n = mActiveTiles.size();
+ for (int i = 0; i < n; i++) {
+ Tile tile = mActiveTiles.valueAt(i);
+ if (!tile.isContentValid()) {
+ queueForDecode(tile);
+ }
+ }
+ }
+
+ private void queueForDecode(Tile tile) {
+ synchronized (mQueueLock) {
+ if (tile.mTileState == STATE_ACTIVATED) {
+ tile.mTileState = STATE_IN_QUEUE;
+ if (mDecodeQueue.push(tile)) {
+ mQueueLock.notifyAll();
+ }
+ }
+ }
+ }
+
+ private void decodeTile(Tile tile) {
+ synchronized (mQueueLock) {
+ if (tile.mTileState != STATE_IN_QUEUE) {
+ return;
+ }
+ tile.mTileState = STATE_DECODING;
+ }
+ boolean decodeComplete = tile.decode();
+ synchronized (mQueueLock) {
+ if (tile.mTileState == STATE_RECYCLING) {
+ tile.mTileState = STATE_RECYCLED;
+ if (tile.mDecodedTile != null) {
+ sTilePool.release(tile.mDecodedTile);
+ tile.mDecodedTile = null;
+ }
+ mRecycledQueue.push(tile);
+ return;
+ }
+ tile.mTileState = decodeComplete ? STATE_DECODED : STATE_DECODE_FAIL;
+ if (!decodeComplete) {
+ return;
+ }
+ mUploadQueue.push(tile);
+ }
+ invalidate();
+ }
+
+ private Tile obtainTile(int x, int y, int level) {
+ synchronized (mQueueLock) {
+ Tile tile = mRecycledQueue.pop();
+ if (tile != null) {
+ tile.mTileState = STATE_ACTIVATED;
+ tile.update(x, y, level);
+ return tile;
+ }
+ return new Tile(x, y, level);
+ }
+ }
+
+ private void recycleTile(Tile tile) {
+ synchronized (mQueueLock) {
+ if (tile.mTileState == STATE_DECODING) {
+ tile.mTileState = STATE_RECYCLING;
+ return;
+ }
+ tile.mTileState = STATE_RECYCLED;
+ if (tile.mDecodedTile != null) {
+ sTilePool.release(tile.mDecodedTile);
+ tile.mDecodedTile = null;
+ }
+ mRecycledQueue.push(tile);
+ }
+ }
+
+ private void activateTile(int x, int y, int level) {
+ long key = makeTileKey(x, y, level);
+ Tile tile = mActiveTiles.get(key);
+ if (tile != null) {
+ if (tile.mTileState == STATE_IN_QUEUE) {
+ tile.mTileState = STATE_ACTIVATED;
+ }
+ return;
+ }
+ tile = obtainTile(x, y, level);
+ mActiveTiles.put(key, tile);
+ }
+
+ private Tile getTile(int x, int y, int level) {
+ return mActiveTiles.get(makeTileKey(x, y, level));
+ }
+
+ private static long makeTileKey(int x, int y, int level) {
+ long result = x;
+ result = (result << 16) | y;
+ result = (result << 16) | level;
+ return result;
+ }
+
+ private void uploadTiles(GLCanvas canvas) {
+ int quota = UPLOAD_LIMIT;
+ Tile tile = null;
+ while (quota > 0) {
+ synchronized (mQueueLock) {
+ tile = mUploadQueue.pop();
+ }
+ if (tile == null) {
+ break;
+ }
+ if (!tile.isContentValid()) {
+ if (tile.mTileState == STATE_DECODED) {
+ tile.updateContent(canvas);
+ --quota;
+ } else {
+ Log.w(TAG, "Tile in upload queue has invalid state: " + tile.mTileState);
+ }
+ }
+ }
+ if (tile != null) {
+ invalidate();
+ }
+ }
+
+ // Draw the tile to a square at canvas that locates at (x, y) and
+ // has a side length of length.
+ private void drawTile(GLCanvas canvas,
+ int tx, int ty, int level, float x, float y, float length) {
+ RectF source = mSourceRect;
+ RectF target = mTargetRect;
+ target.set(x, y, x + length, y + length);
+ source.set(0, 0, mTileSize, mTileSize);
+
+ Tile tile = getTile(tx, ty, level);
+ if (tile != null) {
+ if (!tile.isContentValid()) {
+ if (tile.mTileState == STATE_DECODED) {
+ if (mUploadQuota > 0) {
+ --mUploadQuota;
+ tile.updateContent(canvas);
+ } else {
+ mRenderComplete = false;
+ }
+ } else if (tile.mTileState != STATE_DECODE_FAIL){
+ mRenderComplete = false;
+ queueForDecode(tile);
+ }
+ }
+ if (drawTile(tile, canvas, source, target)) {
+ return;
+ }
+ }
+ if (mPreview != null) {
+ int size = mTileSize << level;
+ float scaleX = (float) mPreview.getWidth() / mImageWidth;
+ float scaleY = (float) mPreview.getHeight() / mImageHeight;
+ source.set(tx * scaleX, ty * scaleY, (tx + size) * scaleX,
+ (ty + size) * scaleY);
+ canvas.drawTexture(mPreview, source, target);
+ }
+ }
+
+ private boolean drawTile(
+ Tile tile, GLCanvas canvas, RectF source, RectF target) {
+ while (true) {
+ if (tile.isContentValid()) {
+ canvas.drawTexture(tile, source, target);
+ return true;
+ }
+
+ // Parent can be divided to four quads and tile is one of the four.
+ Tile parent = tile.getParentTile();
+ if (parent == null) {
+ return false;
+ }
+ if (tile.mX == parent.mX) {
+ source.left /= 2f;
+ source.right /= 2f;
+ } else {
+ source.left = (mTileSize + source.left) / 2f;
+ source.right = (mTileSize + source.right) / 2f;
+ }
+ if (tile.mY == parent.mY) {
+ source.top /= 2f;
+ source.bottom /= 2f;
+ } else {
+ source.top = (mTileSize + source.top) / 2f;
+ source.bottom = (mTileSize + source.bottom) / 2f;
+ }
+ tile = parent;
+ }
+ }
+
+ private class Tile extends UploadedTexture {
+ public int mX;
+ public int mY;
+ public int mTileLevel;
+ public Tile mNext;
+ public Bitmap mDecodedTile;
+ public volatile int mTileState = STATE_ACTIVATED;
+
+ public Tile(int x, int y, int level) {
+ mX = x;
+ mY = y;
+ mTileLevel = level;
+ }
+
+ @Override
+ protected void onFreeBitmap(Bitmap bitmap) {
+ sTilePool.release(bitmap);
+ }
+
+ boolean decode() {
+ // Get a tile from the original image. The tile is down-scaled
+ // by (1 << mTilelevel) from a region in the original image.
+ try {
+ Bitmap reuse = sTilePool.acquire();
+ if (reuse != null && reuse.getWidth() != mTileSize) {
+ reuse = null;
+ }
+ mDecodedTile = mModel.getTile(mTileLevel, mX, mY, reuse);
+ } catch (Throwable t) {
+ Log.w(TAG, "fail to decode tile", t);
+ }
+ return mDecodedTile != null;
+ }
+
+ @Override
+ protected Bitmap onGetBitmap() {
+ Utils.assertTrue(mTileState == STATE_DECODED);
+
+ // We need to override the width and height, so that we won't
+ // draw beyond the boundaries.
+ int rightEdge = ((mImageWidth - mX) >> mTileLevel);
+ int bottomEdge = ((mImageHeight - mY) >> mTileLevel);
+ setSize(Math.min(mTileSize, rightEdge), Math.min(mTileSize, bottomEdge));
+
+ Bitmap bitmap = mDecodedTile;
+ mDecodedTile = null;
+ mTileState = STATE_ACTIVATED;
+ return bitmap;
+ }
+
+ // We override getTextureWidth() and getTextureHeight() here, so the
+ // texture can be re-used for different tiles regardless of the actual
+ // size of the tile (which may be small because it is a tile at the
+ // boundary).
+ @Override
+ public int getTextureWidth() {
+ return mTileSize;
+ }
+
+ @Override
+ public int getTextureHeight() {
+ return mTileSize;
+ }
+
+ public void update(int x, int y, int level) {
+ mX = x;
+ mY = y;
+ mTileLevel = level;
+ invalidateContent();
+ }
+
+ public Tile getParentTile() {
+ if (mTileLevel + 1 == mLevelCount) {
+ return null;
+ }
+ int size = mTileSize << (mTileLevel + 1);
+ int x = size * (mX / size);
+ int y = size * (mY / size);
+ return getTile(x, y, mTileLevel + 1);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("tile(%s, %s, %s / %s)",
+ mX / mTileSize, mY / mTileSize, mLevel, mLevelCount);
+ }
+ }
+
+ private static class TileQueue {
+ private Tile mHead;
+
+ public Tile pop() {
+ Tile tile = mHead;
+ if (tile != null) {
+ mHead = tile.mNext;
+ }
+ return tile;
+ }
+
+ public boolean push(Tile tile) {
+ if (contains(tile)) {
+ Log.w(TAG, "Attempting to add a tile already in the queue!");
+ return false;
+ }
+ boolean wasEmpty = mHead == null;
+ tile.mNext = mHead;
+ mHead = tile;
+ return wasEmpty;
+ }
+
+ private boolean contains(Tile tile) {
+ Tile other = mHead;
+ while (other != null) {
+ if (other == tile) {
+ return true;
+ }
+ other = other.mNext;
+ }
+ return false;
+ }
+
+ public void clean() {
+ mHead = null;
+ }
+ }
+
+ private class TileDecoder extends Thread {
+
+ public void finishAndWait() {
+ interrupt();
+ try {
+ join();
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Interrupted while waiting for TileDecoder thread to finish!");
+ }
+ }
+
+ private Tile waitForTile() throws InterruptedException {
+ synchronized (mQueueLock) {
+ while (true) {
+ Tile tile = mDecodeQueue.pop();
+ if (tile != null) {
+ return tile;
+ }
+ mQueueLock.wait();
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (!isInterrupted()) {
+ Tile tile = waitForTile();
+ decodeTile(tile);
+ }
+ } catch (InterruptedException ex) {
+ // We were finished
+ }
+ }
+
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
new file mode 100644
index 0000000..36cb438
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageView.java
@@ -0,0 +1,386 @@
+/*
+ * 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.photos.views;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.RectF;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.Choreographer;
+import android.view.Choreographer.FrameCallback;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.gallery3d.glrenderer.BasicTexture;
+import com.android.gallery3d.glrenderer.GLES20Canvas;
+import com.android.photos.views.TiledImageRenderer.TileSource;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView}
+ * or {@link BlockingGLTextureView}.
+ */
+public class TiledImageView extends FrameLayout {
+
+ private static final boolean USE_TEXTURE_VIEW = false;
+ private static final boolean IS_SUPPORTED =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+ private static final boolean USE_CHOREOGRAPHER =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+
+ private BlockingGLTextureView mTextureView;
+ private GLSurfaceView mGLSurfaceView;
+ private boolean mInvalPending = false;
+ private FrameCallback mFrameCallback;
+
+ protected static class ImageRendererWrapper {
+ // Guarded by locks
+ public float scale;
+ public int centerX, centerY;
+ int rotation;
+ public TileSource source;
+ Runnable isReadyCallback;
+
+ // GL thread only
+ TiledImageRenderer image;
+ }
+
+ private float[] mValues = new float[9];
+
+ // -------------------------
+ // Guarded by mLock
+ // -------------------------
+ protected Object mLock = new Object();
+ protected ImageRendererWrapper mRenderer;
+
+ public static boolean isTilingSupported() {
+ return IS_SUPPORTED;
+ }
+
+ public TiledImageView(Context context) {
+ this(context, null);
+ }
+
+ public TiledImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ if (!IS_SUPPORTED) {
+ return;
+ }
+
+ mRenderer = new ImageRendererWrapper();
+ mRenderer.image = new TiledImageRenderer(this);
+ View view;
+ if (USE_TEXTURE_VIEW) {
+ mTextureView = new BlockingGLTextureView(context);
+ mTextureView.setRenderer(new TileRenderer());
+ view = mTextureView;
+ } else {
+ mGLSurfaceView = new GLSurfaceView(context);
+ mGLSurfaceView.setEGLContextClientVersion(2);
+ mGLSurfaceView.setRenderer(new TileRenderer());
+ mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+ view = mGLSurfaceView;
+ }
+ addView(view, new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ //setTileSource(new ColoredTiles());
+ }
+
+ public void destroy() {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (USE_TEXTURE_VIEW) {
+ mTextureView.destroy();
+ } else {
+ mGLSurfaceView.queueEvent(mFreeTextures);
+ }
+ }
+
+ private Runnable mFreeTextures = new Runnable() {
+
+ @Override
+ public void run() {
+ mRenderer.image.freeTextures();
+ }
+ };
+
+ public void onPause() {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (!USE_TEXTURE_VIEW) {
+ mGLSurfaceView.onPause();
+ }
+ }
+
+ public void onResume() {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (!USE_TEXTURE_VIEW) {
+ mGLSurfaceView.onResume();
+ }
+ }
+
+ public void setTileSource(TileSource source, Runnable isReadyCallback) {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ synchronized (mLock) {
+ mRenderer.source = source;
+ mRenderer.isReadyCallback = isReadyCallback;
+ mRenderer.centerX = source != null ? source.getImageWidth() / 2 : 0;
+ mRenderer.centerY = source != null ? source.getImageHeight() / 2 : 0;
+ mRenderer.rotation = source != null ? source.getRotation() : 0;
+ mRenderer.scale = 0;
+ updateScaleIfNecessaryLocked(mRenderer);
+ }
+ invalidate();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right,
+ int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ synchronized (mLock) {
+ updateScaleIfNecessaryLocked(mRenderer);
+ }
+ }
+
+ private void updateScaleIfNecessaryLocked(ImageRendererWrapper renderer) {
+ if (renderer == null || renderer.source == null
+ || renderer.scale > 0 || getWidth() == 0) {
+ return;
+ }
+ renderer.scale = Math.min(
+ (float) getWidth() / (float) renderer.source.getImageWidth(),
+ (float) getHeight() / (float) renderer.source.getImageHeight());
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (USE_TEXTURE_VIEW) {
+ mTextureView.render();
+ }
+ super.dispatchDraw(canvas);
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public void setTranslationX(float translationX) {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ super.setTranslationX(translationX);
+ }
+
+ @Override
+ public void invalidate() {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (USE_TEXTURE_VIEW) {
+ super.invalidate();
+ mTextureView.invalidate();
+ } else {
+ if (USE_CHOREOGRAPHER) {
+ invalOnVsync();
+ } else {
+ mGLSurfaceView.requestRender();
+ }
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ private void invalOnVsync() {
+ if (!mInvalPending) {
+ mInvalPending = true;
+ if (mFrameCallback == null) {
+ mFrameCallback = new FrameCallback() {
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ mInvalPending = false;
+ mGLSurfaceView.requestRender();
+ }
+ };
+ }
+ Choreographer.getInstance().postFrameCallback(mFrameCallback);
+ }
+ }
+
+ private RectF mTempRectF = new RectF();
+ public void positionFromMatrix(Matrix matrix) {
+ if (!IS_SUPPORTED) {
+ return;
+ }
+ if (mRenderer.source != null) {
+ final int rotation = mRenderer.source.getRotation();
+ final boolean swap = !(rotation % 180 == 0);
+ final int width = swap ? mRenderer.source.getImageHeight()
+ : mRenderer.source.getImageWidth();
+ final int height = swap ? mRenderer.source.getImageWidth()
+ : mRenderer.source.getImageHeight();
+ mTempRectF.set(0, 0, width, height);
+ matrix.mapRect(mTempRectF);
+ matrix.getValues(mValues);
+ int cx = width / 2;
+ int cy = height / 2;
+ float scale = mValues[Matrix.MSCALE_X];
+ int xoffset = Math.round((getWidth() - mTempRectF.width()) / 2 / scale);
+ int yoffset = Math.round((getHeight() - mTempRectF.height()) / 2 / scale);
+ if (rotation == 90 || rotation == 180) {
+ cx += (mTempRectF.left / scale) - xoffset;
+ } else {
+ cx -= (mTempRectF.left / scale) - xoffset;
+ }
+ if (rotation == 180 || rotation == 270) {
+ cy += (mTempRectF.top / scale) - yoffset;
+ } else {
+ cy -= (mTempRectF.top / scale) - yoffset;
+ }
+ mRenderer.scale = scale;
+ mRenderer.centerX = swap ? cy : cx;
+ mRenderer.centerY = swap ? cx : cy;
+ invalidate();
+ }
+ }
+
+ private class TileRenderer implements Renderer {
+
+ private GLES20Canvas mCanvas;
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ mCanvas = new GLES20Canvas();
+ BasicTexture.invalidateAllTextures();
+ mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ mCanvas.setSize(width, height);
+ mRenderer.image.setViewSize(width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ mCanvas.clearBuffer();
+ Runnable readyCallback;
+ synchronized (mLock) {
+ readyCallback = mRenderer.isReadyCallback;
+ mRenderer.image.setModel(mRenderer.source, mRenderer.rotation);
+ mRenderer.image.setPosition(mRenderer.centerX, mRenderer.centerY,
+ mRenderer.scale);
+ }
+ boolean complete = mRenderer.image.draw(mCanvas);
+ if (complete && readyCallback != null) {
+ synchronized (mLock) {
+ // Make sure we don't trample on a newly set callback/source
+ // if it changed while we were rendering
+ if (mRenderer.isReadyCallback == readyCallback) {
+ mRenderer.isReadyCallback = null;
+ }
+ }
+ if (readyCallback != null) {
+ post(readyCallback);
+ }
+ }
+ }
+
+ }
+
+ @SuppressWarnings("unused")
+ private static class ColoredTiles implements TileSource {
+ private static final int[] COLORS = new int[] {
+ Color.RED,
+ Color.BLUE,
+ Color.YELLOW,
+ Color.GREEN,
+ Color.CYAN,
+ Color.MAGENTA,
+ Color.WHITE,
+ };
+
+ private Paint mPaint = new Paint();
+ private Canvas mCanvas = new Canvas();
+
+ @Override
+ public int getTileSize() {
+ return 256;
+ }
+
+ @Override
+ public int getImageWidth() {
+ return 16384;
+ }
+
+ @Override
+ public int getImageHeight() {
+ return 8192;
+ }
+
+ @Override
+ public int getRotation() {
+ return 0;
+ }
+
+ @Override
+ public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
+ int tileSize = getTileSize();
+ if (bitmap == null) {
+ bitmap = Bitmap.createBitmap(tileSize, tileSize,
+ Bitmap.Config.ARGB_8888);
+ }
+ mCanvas.setBitmap(bitmap);
+ mCanvas.drawColor(COLORS[level]);
+ mPaint.setColor(Color.BLACK);
+ mPaint.setTextSize(20);
+ mPaint.setTextAlign(Align.CENTER);
+ mCanvas.drawText(x + "x" + y, 128, 128, mPaint);
+ tileSize <<= level;
+ x /= tileSize;
+ y /= tileSize;
+ mCanvas.drawText(x + "x" + y + " @ " + level, 128, 30, mPaint);
+ mCanvas.setBitmap(null);
+ return bitmap;
+ }
+
+ @Override
+ public BasicTexture getPreview() {
+ return null;
+ }
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
new file mode 100644
index 0000000..ecebd642
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+/* Copied from Launcher3 */
+package com.android.wallpapercropper;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.ViewConfiguration;
+import android.view.ScaleGestureDetector.OnScaleGestureListener;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+
+import com.android.photos.views.TiledImageRenderer.TileSource;
+import com.android.photos.views.TiledImageView;
+
+public class CropView extends TiledImageView implements OnScaleGestureListener {
+
+ private ScaleGestureDetector mScaleGestureDetector;
+ private long mTouchDownTime;
+ private float mFirstX, mFirstY;
+ private float mLastX, mLastY;
+ private float mMinScale;
+ private boolean mTouchEnabled = true;
+ private RectF mTempEdges = new RectF();
+ TouchCallback mTouchCallback;
+
+ public interface TouchCallback {
+ void onTouchDown();
+ void onTap();
+ }
+
+ public CropView(Context context) {
+ this(context, null);
+ }
+
+ public CropView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mScaleGestureDetector = new ScaleGestureDetector(context, this);
+ }
+
+ private void getEdgesHelper(RectF edgesOut) {
+ final float width = getWidth();
+ final float height = getHeight();
+ final float imageWidth = mRenderer.source.getImageWidth();
+ final float imageHeight = mRenderer.source.getImageHeight();
+ final float scale = mRenderer.scale;
+ float centerX = (width / 2f - mRenderer.centerX + (imageWidth - width) / 2f)
+ * scale + width / 2f;
+ float centerY = (height / 2f - mRenderer.centerY + (imageHeight - height) / 2f)
+ * scale + height / 2f;
+ float leftEdge = centerX - imageWidth / 2f * scale;
+ float rightEdge = centerX + imageWidth / 2f * scale;
+ float topEdge = centerY - imageHeight / 2f * scale;
+ float bottomEdge = centerY + imageHeight / 2f * scale;
+
+ edgesOut.left = leftEdge;
+ edgesOut.right = rightEdge;
+ edgesOut.top = topEdge;
+ edgesOut.bottom = bottomEdge;
+ }
+
+ public RectF getCrop() {
+ final RectF edges = mTempEdges;
+ getEdgesHelper(edges);
+ final float scale = mRenderer.scale;
+
+ float cropLeft = -edges.left / scale;
+ float cropTop = -edges.top / scale;
+ float cropRight = cropLeft + getWidth() / scale;
+ float cropBottom = cropTop + getHeight() / scale;
+
+ return new RectF(cropLeft, cropTop, cropRight, cropBottom);
+ }
+
+ public Point getSourceDimensions() {
+ return new Point(mRenderer.source.getImageWidth(), mRenderer.source.getImageHeight());
+ }
+
+ public void setTileSource(TileSource source, Runnable isReadyCallback) {
+ super.setTileSource(source, isReadyCallback);
+ updateMinScale(getWidth(), getHeight(), source, true);
+ }
+
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ updateMinScale(w, h, mRenderer.source, false);
+ }
+
+ public void setScale(float scale) {
+ synchronized (mLock) {
+ mRenderer.scale = scale;
+ }
+ }
+
+ private void updateMinScale(int w, int h, TileSource source, boolean resetScale) {
+ synchronized (mLock) {
+ if (resetScale) {
+ mRenderer.scale = 1;
+ }
+ if (source != null) {
+ mMinScale = Math.max(w / (float) source.getImageWidth(),
+ h / (float) source.getImageHeight());
+ mRenderer.scale = Math.max(mMinScale, mRenderer.scale);
+ }
+ }
+ }
+
+ @Override
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ return true;
+ }
+
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ // Don't need the lock because this will only fire inside of
+ // onTouchEvent
+ mRenderer.scale *= detector.getScaleFactor();
+ mRenderer.scale = Math.max(mMinScale, mRenderer.scale);
+ invalidate();
+ return true;
+ }
+
+ @Override
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ }
+
+ public void moveToUpperLeft() {
+ if (getWidth() == 0 || getHeight() == 0) {
+ final ViewTreeObserver observer = getViewTreeObserver();
+ observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ moveToUpperLeft();
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ });
+ }
+ final RectF edges = mTempEdges;
+ getEdgesHelper(edges);
+ final float scale = mRenderer.scale;
+ mRenderer.centerX += Math.ceil(edges.left / scale);
+ mRenderer.centerY += Math.ceil(edges.top / scale);
+ }
+
+ public void setTouchEnabled(boolean enabled) {
+ mTouchEnabled = enabled;
+ }
+
+ public void setTouchCallback(TouchCallback cb) {
+ mTouchCallback = cb;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+ final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
+ final int skipIndex = pointerUp ? event.getActionIndex() : -1;
+
+ // Determine focal point
+ float sumX = 0, sumY = 0;
+ final int count = event.getPointerCount();
+ for (int i = 0; i < count; i++) {
+ if (skipIndex == i)
+ continue;
+ sumX += event.getX(i);
+ sumY += event.getY(i);
+ }
+ final int div = pointerUp ? count - 1 : count;
+ float x = sumX / div;
+ float y = sumY / div;
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ mFirstX = x;
+ mFirstY = y;
+ mTouchDownTime = System.currentTimeMillis();
+ if (mTouchCallback != null) {
+ mTouchCallback.onTouchDown();
+ }
+ } else if (action == MotionEvent.ACTION_UP) {
+ ViewConfiguration config = ViewConfiguration.get(getContext());
+
+ float squaredDist = (mFirstX - x) * (mFirstX - x) + (mFirstY - y) * (mFirstY - y);
+ float slop = config.getScaledTouchSlop() * config.getScaledTouchSlop();
+ long now = System.currentTimeMillis();
+ // only do this if it's a small movement
+ if (mTouchCallback != null &&
+ squaredDist < slop &&
+ now < mTouchDownTime + ViewConfiguration.getTapTimeout()) {
+ mTouchCallback.onTap();
+ }
+ }
+
+ if (!mTouchEnabled) {
+ return true;
+ }
+
+ synchronized (mLock) {
+ mScaleGestureDetector.onTouchEvent(event);
+ switch (action) {
+ case MotionEvent.ACTION_MOVE:
+ mRenderer.centerX += (mLastX - x) / mRenderer.scale;
+ mRenderer.centerY += (mLastY - y) / mRenderer.scale;
+ invalidate();
+ break;
+ }
+ if (mRenderer.source != null) {
+ // Adjust position so that the wallpaper covers the entire area
+ // of the screen
+ final RectF edges = mTempEdges;
+ getEdgesHelper(edges);
+ final float scale = mRenderer.scale;
+ if (edges.left > 0) {
+ mRenderer.centerX += Math.ceil(edges.left / scale);
+ }
+ if (edges.right < getWidth()) {
+ mRenderer.centerX += (edges.right - getWidth()) / scale;
+ }
+ if (edges.top > 0) {
+ mRenderer.centerY += Math.ceil(edges.top / scale);
+ }
+ if (edges.bottom < getHeight()) {
+ mRenderer.centerY += (edges.bottom - getHeight()) / scale;
+ }
+ }
+ }
+
+ mLastX = x;
+ mLastY = y;
+ return true;
+ }
+}
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
new file mode 100644
index 0000000..a993ed3
--- /dev/null
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -0,0 +1,646 @@
+/*
+ * 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.
+ */
+/* Copied from Launcher3 */
+package com.android.wallpapercropper;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.gallery3d.common.Utils;
+import com.android.photos.BitmapRegionTileSource;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class WallpaperCropActivity extends Activity {
+ private static final String LOGTAG = "Launcher3.CropActivity";
+
+ protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width";
+ protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height";
+ private static final int DEFAULT_COMPRESS_QUALITY = 90;
+ /**
+ * The maximum bitmap size we allow to be returned through the intent.
+ * Intents have a maximum of 1MB in total size. However, the Bitmap seems to
+ * have some overhead to hit so that we go way below the limit here to make
+ * sure the intent stays below 1MB.We should consider just returning a byte
+ * array instead of a Bitmap instance to avoid overhead.
+ */
+ public static final int MAX_BMAP_IN_INTENT = 750000;
+ private static final float WALLPAPER_SCREENS_SPAN = 2f;
+
+ protected CropView mCropView;
+ protected Uri mUri;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ init();
+ }
+
+ protected void init() {
+ setContentView(R.layout.wallpaper_cropper);
+
+ mCropView = (CropView) findViewById(R.id.cropView);
+
+ Intent cropIntent = this.getIntent();
+ final Uri imageUri = cropIntent.getData();
+
+ mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, 0), null);
+ mCropView.setTouchEnabled(true);
+ // Action bar
+ // Show the custom action bar view
+ final ActionBar actionBar = getActionBar();
+ actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
+ actionBar.getCustomView().setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean finishActivityWhenDone = true;
+ cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
+ }
+ });
+ }
+
+ public static String getSharedPreferencesKey() {
+ return WallpaperCropActivity.class.getName();
+ }
+
+ // As a ratio of screen height, the total distance we want the parallax effect to span
+ // horizontally
+ private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
+ float aspectRatio = width / (float) height;
+
+ // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
+ // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
+ // We will use these two data points to extrapolate how much the wallpaper parallax effect
+ // to span (ie travel) at any aspect ratio:
+
+ final float ASPECT_RATIO_LANDSCAPE = 16/10f;
+ final float ASPECT_RATIO_PORTRAIT = 10/16f;
+ final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
+ final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
+
+ // To find out the desired width at different aspect ratios, we use the following two
+ // formulas, where the coefficient on x is the aspect ratio (width/height):
+ // (16/10)x + y = 1.5
+ // (10/16)x + y = 1.2
+ // We solve for x and y and end up with a final formula:
+ final float x =
+ (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
+ (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
+ final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
+ return x * aspectRatio + y;
+ }
+
+ static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
+ Point minDims = new Point();
+ Point maxDims = new Point();
+ windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
+
+ int maxDim = Math.max(maxDims.x, maxDims.y);
+ final int minDim = Math.min(minDims.x, minDims.y);
+
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ Point realSize = new Point();
+ windowManager.getDefaultDisplay().getRealSize(realSize);
+ maxDim = Math.max(realSize.x, realSize.y);
+ }
+
+ // We need to ensure that there is enough extra space in the wallpaper
+ // for the intended
+ // parallax effects
+ final int defaultWidth, defaultHeight;
+ if (isScreenLarge(res)) {
+ defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+ defaultHeight = maxDim;
+ } else {
+ defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
+ defaultHeight = maxDim;
+ }
+ return new Point(defaultWidth, defaultHeight);
+ }
+
+ protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) {
+
+ BitmapCropTask cropTask = new BitmapCropTask(this,
+ filePath, null, 0, 0, true, false, null);
+ final Point bounds = cropTask.getImageBounds();
+ Runnable onEndCrop = new Runnable() {
+ public void run() {
+ updateWallpaperDimensions(bounds.x, bounds.y);
+ if (finishActivityWhenDone) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+ }
+ };
+ cropTask.setOnEndRunnable(onEndCrop);
+ cropTask.setNoCrop(true);
+ cropTask.execute();
+ }
+
+ protected void cropImageAndSetWallpaper(
+ Resources res, int resId, final boolean finishActivityWhenDone) {
+ // crop this image and scale it down to the default wallpaper size for
+ // this device
+ Point inSize = mCropView.getSourceDimensions();
+ Point outSize = getDefaultWallpaperSize(getResources(),
+ getWindowManager());
+ RectF crop = getMaxCropRect(
+ inSize.x, inSize.y, outSize.x, outSize.y, false);
+ Runnable onEndCrop = new Runnable() {
+ public void run() {
+ // Passing 0, 0 will cause launcher to revert to using the
+ // default wallpaper size
+ updateWallpaperDimensions(0, 0);
+ if (finishActivityWhenDone) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+ }
+ };
+ BitmapCropTask cropTask = new BitmapCropTask(res, resId,
+ crop, outSize.x, outSize.y,
+ true, false, onEndCrop);
+ cropTask.execute();
+ }
+
+ private static boolean isScreenLarge(Resources res) {
+ Configuration config = res.getConfiguration();
+ return config.smallestScreenWidthDp >= 720;
+ }
+
+ protected void cropImageAndSetWallpaper(Uri uri,
+ OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
+ // Get the crop
+ Point inSize = mCropView.getSourceDimensions();
+
+ Point minDims = new Point();
+ Point maxDims = new Point();
+ Display d = getWindowManager().getDefaultDisplay();
+ d.getCurrentSizeRange(minDims, maxDims);
+
+ Point displaySize = new Point();
+ d.getSize(displaySize);
+
+ int maxDim = Math.max(maxDims.x, maxDims.y);
+ final int minDim = Math.min(minDims.x, minDims.y);
+ int defaultWidth;
+ if (isScreenLarge(getResources())) {
+ defaultWidth = (int) (maxDim *
+ wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+ } else {
+ defaultWidth = Math.max((int)
+ (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
+ }
+
+ boolean isPortrait = displaySize.x < displaySize.y;
+ int portraitHeight;
+ if (isPortrait) {
+ portraitHeight = mCropView.getHeight();
+ } else {
+ // TODO: how to actually get the proper portrait height?
+ // This is not quite right:
+ portraitHeight = Math.max(maxDims.x, maxDims.y);
+ }
+ if (android.os.Build.VERSION.SDK_INT >=
+ android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ Point realSize = new Point();
+ d.getRealSize(realSize);
+ portraitHeight = Math.max(realSize.x, realSize.y);
+ }
+ // Get the crop
+ RectF cropRect = mCropView.getCrop();
+ float cropScale = mCropView.getWidth() / (float) cropRect.width();
+
+ // ADJUST CROP WIDTH
+ // Extend the crop all the way to the right, for parallax
+ float extraSpaceToRight = inSize.x - cropRect.right;
+ // Cap the amount of extra width
+ float maxExtraSpace = defaultWidth / cropScale - cropRect.width();
+ extraSpaceToRight = Math.min(extraSpaceToRight, maxExtraSpace);
+
+ cropRect.right += extraSpaceToRight;
+
+ // ADJUST CROP HEIGHT
+ if (isPortrait) {
+ cropRect.bottom = cropRect.top + portraitHeight / cropScale;
+ } else { // LANDSCAPE
+ float extraPortraitHeight =
+ portraitHeight / cropScale - cropRect.height();
+ float expandHeight =
+ Math.min(Math.min(inSize.y - cropRect.bottom, cropRect.top),
+ extraPortraitHeight / 2);
+ cropRect.top -= expandHeight;
+ cropRect.bottom += expandHeight;
+ }
+ final int outWidth = (int) Math.round(cropRect.width() * cropScale);
+ final int outHeight = (int) Math.round(cropRect.height() * cropScale);
+
+ Runnable onEndCrop = new Runnable() {
+ public void run() {
+ updateWallpaperDimensions(outWidth, outHeight);
+ if (finishActivityWhenDone) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+ }
+ };
+ BitmapCropTask cropTask = new BitmapCropTask(uri,
+ cropRect, outWidth, outHeight, true, false, onEndCrop);
+ if (onBitmapCroppedHandler != null) {
+ cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
+ }
+ cropTask.execute();
+ }
+
+ public interface OnBitmapCroppedHandler {
+ public void onBitmapCropped(byte[] imageBytes);
+ }
+
+ protected class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
+ Uri mInUri = null;
+ Context mContext;
+ String mInFilePath;
+ byte[] mInImageBytes;
+ int mInResId = 0;
+ InputStream mInStream;
+ RectF mCropBounds = null;
+ int mOutWidth, mOutHeight;
+ int mRotation = 0; // for now
+ protected final WallpaperManager mWPManager;
+ String mOutputFormat = "jpg"; // for now
+ boolean mSetWallpaper;
+ boolean mSaveCroppedBitmap;
+ Bitmap mCroppedBitmap;
+ Runnable mOnEndRunnable;
+ Resources mResources;
+ OnBitmapCroppedHandler mOnBitmapCroppedHandler;
+ boolean mNoCrop;
+
+ public BitmapCropTask(Context c, String filePath,
+ RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mContext = c;
+ mInFilePath = filePath;
+ mWPManager = WallpaperManager.getInstance(getApplicationContext());
+ init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ public BitmapCropTask(byte[] imageBytes,
+ RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mInImageBytes = imageBytes;
+ mWPManager = WallpaperManager.getInstance(getApplicationContext());
+ init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ public BitmapCropTask(Uri inUri,
+ RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mInUri = inUri;
+ mWPManager = WallpaperManager.getInstance(getApplicationContext());
+ init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ public BitmapCropTask(Resources res, int inResId,
+ RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mInResId = inResId;
+ mResources = res;
+ mWPManager = WallpaperManager.getInstance(getApplicationContext());
+ init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+ }
+
+ private void init(RectF cropBounds, int outWidth, int outHeight,
+ boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+ mCropBounds = cropBounds;
+ mOutWidth = outWidth;
+ mOutHeight = outHeight;
+ mSetWallpaper = setWallpaper;
+ mSaveCroppedBitmap = saveCroppedBitmap;
+ mOnEndRunnable = onEndRunnable;
+ }
+
+ public void setOnBitmapCropped(OnBitmapCroppedHandler handler) {
+ mOnBitmapCroppedHandler = handler;
+ }
+
+ public void setNoCrop(boolean value) {
+ mNoCrop = value;
+ }
+
+ public void setOnEndRunnable(Runnable onEndRunnable) {
+ mOnEndRunnable = onEndRunnable;
+ }
+
+ // Helper to setup input stream
+ private void regenerateInputStream() {
+ if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) {
+ Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " +
+ "image byte array given");
+ } else {
+ Utils.closeSilently(mInStream);
+ try {
+ if (mInUri != null) {
+ mInStream = new BufferedInputStream(
+ getContentResolver().openInputStream(mInUri));
+ } else if (mInFilePath != null) {
+ mInStream = mContext.openFileInput(mInFilePath);
+ } else if (mInImageBytes != null) {
+ mInStream = new BufferedInputStream(
+ new ByteArrayInputStream(mInImageBytes));
+ } else {
+ mInStream = new BufferedInputStream(
+ mResources.openRawResource(mInResId));
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);
+ }
+ }
+ }
+
+ public Point getImageBounds() {
+ regenerateInputStream();
+ if (mInStream != null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(mInStream, null, options);
+ if (options.outWidth != 0 && options.outHeight != 0) {
+ return new Point(options.outWidth, options.outHeight);
+ }
+ }
+ return null;
+ }
+
+ public void setCropBounds(RectF cropBounds) {
+ mCropBounds = cropBounds;
+ }
+
+ public Bitmap getCroppedBitmap() {
+ return mCroppedBitmap;
+ }
+ public boolean cropBitmap() {
+ boolean failure = false;
+
+ regenerateInputStream();
+
+ if (mNoCrop && mInStream != null) {
+ try {
+ mWPManager.setStream(mInStream);
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+ failure = true;
+ }
+ if (mOnEndRunnable != null) {
+ mOnEndRunnable.run();
+ }
+ return !failure;
+ }
+ if (mInStream != null) {
+ // Find crop bounds (scaled to original image size)
+ Rect roundedTrueCrop = new Rect();
+ mCropBounds.roundOut(roundedTrueCrop);
+
+ if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
+ Log.w(LOGTAG, "crop has bad values for full size image");
+ failure = true;
+ return false;
+ }
+
+ // See how much we're reducing the size of the image
+ int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / mOutWidth,
+ roundedTrueCrop.height() / mOutHeight);
+
+ // Attempt to open a region decoder
+ BitmapRegionDecoder decoder = null;
+ try {
+ decoder = BitmapRegionDecoder.newInstance(mInStream, true);
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
+ }
+
+ Bitmap crop = null;
+ if (decoder != null) {
+ // Do region decoding to get crop bitmap
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ if (scaleDownSampleSize > 1) {
+ options.inSampleSize = scaleDownSampleSize;
+ }
+ crop = decoder.decodeRegion(roundedTrueCrop, options);
+ decoder.recycle();
+ }
+
+ if (crop == null) {
+ // BitmapRegionDecoder has failed, try to crop in-memory
+ regenerateInputStream();
+ Bitmap fullSize = null;
+ if (mInStream != null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ if (scaleDownSampleSize > 1) {
+ options.inSampleSize = scaleDownSampleSize;
+ }
+ fullSize = BitmapFactory.decodeStream(mInStream, null, options);
+ }
+ if (fullSize != null) {
+ crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
+ roundedTrueCrop.top, roundedTrueCrop.width(),
+ roundedTrueCrop.height());
+ }
+ }
+
+ if (crop == null) {
+ Log.w(LOGTAG, "cannot decode file: " + mInUri.toString());
+ failure = true;
+ return false;
+ }
+ if (mOutWidth > 0 && mOutHeight > 0) {
+ Matrix m = new Matrix();
+ RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight());
+ if (mRotation > 0) {
+ m.setRotate(mRotation);
+ m.mapRect(cropRect);
+ }
+ RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
+ m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+ m.preRotate(mRotation);
+ Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
+ (int) returnRect.height(), Bitmap.Config.ARGB_8888);
+ if (tmp != null) {
+ Canvas c = new Canvas(tmp);
+ c.drawBitmap(crop, m, new Paint());
+ crop = tmp;
+ }
+ } else if (mRotation > 0) {
+ Matrix m = new Matrix();
+ m.setRotate(mRotation);
+ Bitmap tmp = Bitmap.createBitmap(crop, 0, 0, crop.getWidth(),
+ crop.getHeight(), m, true);
+ if (tmp != null) {
+ crop = tmp;
+ }
+ }
+
+ if (mSaveCroppedBitmap) {
+ mCroppedBitmap = crop;
+ }
+
+ // Get output compression format
+ CompressFormat cf =
+ convertExtensionToCompressFormat(getFileExtension(mOutputFormat));
+
+ // Compress to byte array
+ ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
+ if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
+ // If we need to set to the wallpaper, set it
+ if (mSetWallpaper && mWPManager != null) {
+ if (mWPManager == null) {
+ Log.w(LOGTAG, "no wallpaper manager");
+ failure = true;
+ } else {
+ try {
+ byte[] outByteArray = tmpOut.toByteArray();
+ mWPManager.setStream(new ByteArrayInputStream(outByteArray));
+ if (mOnBitmapCroppedHandler != null) {
+ mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
+ }
+ } catch (IOException e) {
+ Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+ failure = true;
+ }
+ }
+ }
+ if (mOnEndRunnable != null) {
+ mOnEndRunnable.run();
+ }
+ } else {
+ Log.w(LOGTAG, "cannot compress bitmap");
+ failure = true;
+ }
+ }
+ return !failure; // True if any of the operations failed
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ return cropBitmap();
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ setResult(Activity.RESULT_OK);
+ finish();
+ }
+ }
+
+ protected void updateWallpaperDimensions(int width, int height) {
+ String spKey = getSharedPreferencesKey();
+ SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sp.edit();
+ if (width != 0 && height != 0) {
+ editor.putInt(WALLPAPER_WIDTH_KEY, width);
+ editor.putInt(WALLPAPER_HEIGHT_KEY, height);
+ } else {
+ editor.remove(WALLPAPER_WIDTH_KEY);
+ editor.remove(WALLPAPER_HEIGHT_KEY);
+ }
+ editor.commit();
+
+ suggestWallpaperDimension(getResources(),
+ sp, getWindowManager(), WallpaperManager.getInstance(this));
+ }
+
+ static public void suggestWallpaperDimension(Resources res,
+ final SharedPreferences sharedPrefs,
+ WindowManager windowManager,
+ final WallpaperManager wallpaperManager) {
+ final Point defaultWallpaperSize =
+ WallpaperCropActivity.getDefaultWallpaperSize(res, windowManager);
+
+ new Thread("suggestWallpaperDimension") {
+ public void run() {
+ // If we have saved a wallpaper width/height, use that instead
+ int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x);
+ int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y);
+ wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight);
+ }
+ }.start();
+ }
+
+
+ protected static RectF getMaxCropRect(
+ int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
+ RectF cropRect = new RectF();
+ // Get a crop rect that will fit this
+ if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
+ cropRect.top = 0;
+ cropRect.bottom = inHeight;
+ cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
+ cropRect.right = inWidth - cropRect.left;
+ if (leftAligned) {
+ cropRect.right -= cropRect.left;
+ cropRect.left = 0;
+ }
+ } else {
+ cropRect.left = 0;
+ cropRect.right = inWidth;
+ cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
+ cropRect.bottom = inHeight - cropRect.top;
+ }
+ return cropRect;
+ }
+
+ protected static CompressFormat convertExtensionToCompressFormat(String extension) {
+ return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG;
+ }
+
+ protected static String getFileExtension(String requestFormat) {
+ String outputFormat = (requestFormat == null)
+ ? "jpg"
+ : requestFormat;
+ outputFormat = outputFormat.toLowerCase();
+ return (outputFormat.equals("png") || outputFormat.equals("gif"))
+ ? "png" // We don't support gif compression.
+ : "jpg";
+ }
+}
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index 41b2fd1..57c9675 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -33,7 +33,7 @@
* Controls state/behavior specific to a system bar window.
*/
public class BarController {
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final int TRANSIENT_BAR_NONE = 0;
private static final int TRANSIENT_BAR_SHOWING = 1;
@@ -106,24 +106,32 @@
mPendingShow = true;
return false;
}
- final boolean oldVis = mWin.isVisibleLw();
- final boolean oldAnim = mWin.isAnimatingLw();
- final boolean rt = show ? mWin.showLw(true) : mWin.hideLw(true);
- final int state = computeState(oldVis, oldAnim, mWin.isVisibleLw(), mWin.isAnimatingLw());
- if (state > -1 && mWin.hasDrawnLw()) {
- updateState(state);
+ final boolean wasVis = mWin.isVisibleLw();
+ final boolean wasAnim = mWin.isAnimatingLw();
+ final boolean change = show ? mWin.showLw(true) : mWin.hideLw(true);
+ final int state = computeStateLw(wasVis, wasAnim, mWin, change);
+ updateStateLw(state);
+ return change;
+ }
+
+ private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
+ if (win.hasDrawnLw()) {
+ final boolean vis = win.isVisibleLw();
+ final boolean anim = win.isAnimatingLw();
+ if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
+ return StatusBarManager.WINDOW_STATE_HIDDEN;
+ } else if (change) {
+ if (wasVis && vis && !wasAnim && anim) {
+ return StatusBarManager.WINDOW_STATE_HIDING;
+ } else {
+ return StatusBarManager.WINDOW_STATE_SHOWING;
+ }
+ }
}
- return rt;
+ return mState;
}
- private int computeState(boolean oldVis, boolean oldAnim, boolean newVis, boolean newAnim) {
- return (!newVis && !newAnim) ? StatusBarManager.WINDOW_STATE_HIDDEN
- : (!oldVis && newVis && newAnim) ? StatusBarManager.WINDOW_STATE_SHOWING
- : (oldVis && newVis && !oldAnim && newAnim) ? StatusBarManager.WINDOW_STATE_HIDING
- : -1;
- }
-
- private void updateState(final int state) {
+ private void updateStateLw(final int state) {
if (state != mState) {
mState = state;
if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
@@ -148,7 +156,7 @@
public boolean checkHiddenLw() {
if (mWin != null && mWin.hasDrawnLw()) {
if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
- updateState(StatusBarManager.WINDOW_STATE_HIDDEN);
+ updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
}
if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
// Finished animating out, clean up and reset style
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8a285e3..0782cfb 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -34,7 +34,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -105,7 +104,6 @@
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.HashSet;
import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
@@ -531,7 +529,7 @@
Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
- ImmersiveModeTesting.ENABLED_SETTING), false, this,
+ Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS), false, this,
UserHandle.USER_ALL);
updateSettings();
}
@@ -947,9 +945,7 @@
}
@Override
public void onDebug() {
- if (ImmersiveModeTesting.enabled) {
- ImmersiveModeTesting.toggleForceImmersiveMode(mFocusedWindow, mContext);
- }
+ // no-op
}
});
mTransientNavigationConfirmation = new TransientNavigationConfirmation(mContext);
@@ -1168,8 +1164,9 @@
mHasSoftInput = hasSoftInput;
updateRotation = true;
}
- ImmersiveModeTesting.enabled = Settings.System.getIntForUser(resolver,
- ImmersiveModeTesting.ENABLED_SETTING, 0, UserHandle.USER_CURRENT) != 0;
+ if (mTransientNavigationConfirmation != null) {
+ mTransientNavigationConfirmation.loadSetting();
+ }
}
if (updateRotation) {
updateRotation(true);
@@ -2819,7 +2816,7 @@
// If the status bar is hidden, we don't want to cause
// windows behind it to scroll.
- if (mStatusBar.isVisibleLw() && !statusBarTransient && !statusBarTransparent) {
+ if (mStatusBar.isVisibleLw() && !statusBarTransient) {
// Status bar may go away, so the screen area it occupies
// is available to apps but just covering them when the
// status bar is visible.
@@ -3892,9 +3889,8 @@
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
- if (isScreenOn && isTransientNavigationAllowed(mLastSystemUiFlags)) {
- mTransientNavigationConfirmation.unconfirmLastPackage();
- }
+ mTransientNavigationConfirmation.onPowerKeyDown(isScreenOn, event.getDownTime(),
+ isTransientNavigationAllowed(mLastSystemUiFlags));
if (isScreenOn && !mPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mPowerKeyTriggered = true;
@@ -4173,6 +4169,7 @@
}
if (sb) mStatusBarController.showTransient();
if (nb) mNavigationBarController.showTransient();
+ mTransientNavigationConfirmation.confirmCurrentPrompt();
updateSystemUiVisibilityLw();
}
}
@@ -5039,10 +5036,6 @@
}
private int updateSystemBarsLw(int oldVis, int vis) {
- if (ImmersiveModeTesting.enabled) {
- vis = ImmersiveModeTesting.applyForced(mFocusedWindow, vis);
- }
-
// prevent status bar interaction from clearing certain flags
boolean statusBarHasFocus = mFocusedWindow.getAttrs().type == TYPE_STATUS_BAR;
if (statusBarHasFocus) {
@@ -5086,8 +5079,7 @@
boolean isTransientNav = isTransientNavigationAllowed(vis);
if (mFocusedWindow != null && oldTransientNav != isTransientNav) {
final String pkg = mFocusedWindow.getOwningPackage();
- mTransientNavigationConfirmation.transientNavigationChanged(mCurrentUserId, pkg,
- isTransientNav);
+ mTransientNavigationConfirmation.transientNavigationChanged(pkg, isTransientNav);
}
vis = mNavigationBarController.updateVisibilityLw(isTransientNav, oldVis, vis);
@@ -5104,53 +5096,6 @@
&& (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
}
- // Temporary helper that allows testing immersive mode on existing apps
- // TODO remove
- private static final class ImmersiveModeTesting {
- static String ENABLED_SETTING = "immersive_mode_testing_enabled";
- static boolean enabled = false;
- private static final HashSet<String> sForced = new HashSet<String>();
-
- private static String parseActivity(WindowState win) {
- if (win != null && win.getAppToken() != null) {
- String str = win.getAppToken().toString();
- int end = str.lastIndexOf(' ');
- if (end > 0) {
- int start = str.lastIndexOf(' ', end - 1);
- if (start > -1) {
- return str.substring(start + 1, end);
- }
- }
- }
- return null;
- }
-
- public static int applyForced(WindowState focused, int vis) {
- if (sForced.contains(parseActivity(focused))) {
- vis |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_IMMERSIVE;
- }
- return vis;
- }
-
- public static void toggleForceImmersiveMode(WindowState focused, Context context) {
- String activity = parseActivity(focused);
- if (activity != null) {
- String action;
- if (sForced.contains(activity)) {
- sForced.remove(activity);
- action = "Force immersive mode disabled";
- } else {
- sForced.add(activity);
- action = "Force immersive mode enabled";
- }
- android.widget.Toast.makeText(context,
- action + " for " + activity, android.widget.Toast.LENGTH_SHORT).show();
- }
- }
- }
-
// Use this instead of checking config_showNavigationBar so that it can be consistently
// overridden by qemu.hw.mainkeys in the emulator.
@Override
diff --git a/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
index 3c4f092..8613088 100644
--- a/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
+++ b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
@@ -19,16 +19,20 @@
import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.view.View;
import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.widget.Toast;
import com.android.internal.R;
+import java.util.Arrays;
+
/**
* Helper to manage showing/hiding a confirmation prompt when the transient navigation bar
* is hidden.
@@ -39,16 +43,22 @@
private final Context mContext;
private final H mHandler;
- private final ArraySet<String> mConfirmedUserPackages = new ArraySet<String>();
+ private final ArraySet<String> mConfirmedPackages = new ArraySet<String>();
private final long mShowDelayMs;
+ private final long mPanicThresholdMs;
private Toast mToast;
- private String mLastUserPackage;
+ private String mLastPackage;
+ private String mPromptPackage;
+ private long mPanicTime;
+ private String mPanicPackage;
public TransientNavigationConfirmation(Context context) {
mContext = context;
mHandler = new H();
mShowDelayMs = getNavBarExitDuration() * 3;
+ mPanicThresholdMs = context.getResources()
+ .getInteger(R.integer.config_transient_navigation_confirmation_panic);
}
private long getNavBarExitDuration() {
@@ -56,44 +66,97 @@
return exit != null ? exit.getDuration() : 0;
}
- public void transientNavigationChanged(int userId, String pkg, boolean isNavTransient) {
+ public void loadSetting() {
+ if (DEBUG) Slog.d(TAG, "loadSetting()");
+ mConfirmedPackages.clear();
+ String packages = null;
+ try {
+ packages = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
+ UserHandle.USER_CURRENT);
+ if (packages != null) {
+ mConfirmedPackages.addAll(Arrays.asList(packages.split(",")));
+ if (DEBUG) Slog.d(TAG, "Loaded mConfirmedPackages=" + mConfirmedPackages);
+ }
+ } catch (Throwable t) {
+ Slog.w(TAG, "Error loading confirmations, packages=" + packages, t);
+ }
+ }
+
+ private void saveSetting() {
+ if (DEBUG) Slog.d(TAG, "saveSetting()");
+ try {
+ final String packages = TextUtils.join(",", mConfirmedPackages);
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
+ packages,
+ UserHandle.USER_CURRENT);
+ if (DEBUG) Slog.d(TAG, "Saved packages=" + packages);
+ } catch (Throwable t) {
+ Slog.w(TAG, "Error saving confirmations, mConfirmedPackages=" + mConfirmedPackages, t);
+ }
+ }
+
+ public void transientNavigationChanged(String pkg, boolean isNavTransient) {
if (pkg == null) {
return;
}
- String userPkg = userId + ":" + pkg;
mHandler.removeMessages(H.SHOW);
if (isNavTransient) {
- mLastUserPackage = userPkg;
- if (!mConfirmedUserPackages.contains(userPkg)) {
- if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + userPkg);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, userPkg), mShowDelayMs);
+ mLastPackage = pkg;
+ if (!mConfirmedPackages.contains(pkg)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, pkg), mShowDelayMs);
}
} else {
- mLastUserPackage = null;
- if (DEBUG) Slog.d(TAG, "Hiding transient navigation confirmation for " + userPkg);
+ mLastPackage = null;
mHandler.sendEmptyMessage(H.HIDE);
}
}
- public void unconfirmLastPackage() {
- if (mLastUserPackage != null) {
- if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + mLastUserPackage);
- mConfirmedUserPackages.remove(mLastUserPackage);
+ public void onPowerKeyDown(boolean isScreenOn, long time, boolean transientNavigationAllowed) {
+ if (mPanicPackage != null && !isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
+ // turning the screen back on within the panic threshold
+ unconfirmPackage(mPanicPackage);
+ }
+ if (isScreenOn && transientNavigationAllowed) {
+ // turning the screen off, remember if we were hiding the transient nav
+ mPanicTime = time;
+ mPanicPackage = mLastPackage;
+ } else {
+ mPanicTime = 0;
+ mPanicPackage = null;
+ }
+ }
+
+ public void confirmCurrentPrompt() {
+ mHandler.post(confirmAction(mPromptPackage));
+ }
+
+ private void unconfirmPackage(String pkg) {
+ if (pkg != null) {
+ if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + pkg);
+ mConfirmedPackages.remove(pkg);
+ saveSetting();
}
}
private void handleHide() {
if (mToast != null) {
+ if (DEBUG) Slog.d(TAG,
+ "Hiding transient navigation confirmation for " + mPromptPackage);
mToast.cancel();
mToast = null;
}
}
- private void handleShow(String userPkg) {
+ private void handleShow(String pkg) {
+ mPromptPackage = pkg;
+ if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + pkg);
+
// create the confirmation toast bar
final int msg = R.string.transient_navigation_confirmation;
mToast = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE);
- mToast.setAction(R.string.ok, confirmAction(userPkg));
+ mToast.setAction(R.string.ok, confirmAction(pkg));
// we will be hiding the nav bar, so layout as if it's already hidden
mToast.getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
@@ -102,11 +165,15 @@
mToast.show();
}
- private Runnable confirmAction(final String userPkg) {
+ private Runnable confirmAction(final String pkg) {
return new Runnable() {
@Override
public void run() {
- mConfirmedUserPackages.add(userPkg);
+ if (pkg != null && !mConfirmedPackages.contains(pkg)) {
+ if (DEBUG) Slog.d(TAG, "Confirming transient navigation for " + pkg);
+ mConfirmedPackages.add(pkg);
+ saveSetting();
+ }
handleHide();
}
};
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index c4eb7a4..f3ebdb2 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1305,9 +1305,6 @@
mTransports.put(name, transport);
} else {
mTransports.remove(name);
- if ((mCurrentTransport != null) && mCurrentTransport.equals(name)) {
- mCurrentTransport = null;
- }
// Nothing further to do in the unregistration case
return;
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 19b762d..3f13f3a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2953,8 +2953,11 @@
if (ConnectivityManager.isNetworkTypeMobile(info.getType())
&& (0 != Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0))
- && ((state == NetworkInfo.State.CONNECTED)
- || info.isConnectedToProvisioningNetwork())) {
+ && (((state == NetworkInfo.State.CONNECTED)
+ && (info.getType() == ConnectivityManager.TYPE_MOBILE))
+ || info.isConnectedToProvisioningNetwork())) {
+ log("ConnectivityChange checkMobileProvisioning for"
+ + " TYPE_MOBILE or ProvisioningNetwork");
checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS);
}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 7e83396..8cc80f7 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import com.android.internal.R;
import com.android.internal.os.storage.ExternalStorageFormatter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
@@ -33,6 +34,9 @@
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppGlobals;
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
@@ -51,6 +55,7 @@
import android.content.pm.Signature;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -100,6 +105,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -123,6 +129,8 @@
protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
+ private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
+
private static final boolean DBG = false;
final Context mContext;
@@ -130,9 +138,16 @@
IPowerManager mIPowerManager;
IWindowManager mIWindowManager;
+ NotificationManager mNotificationManager;
private DeviceOwner mDeviceOwner;
+ /**
+ * Whether or not device admin feature is supported. If it isn't return defaults for all
+ * public methods.
+ */
+ private boolean mHasFeature;
+
public static class DevicePolicyData {
int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
int mActivePasswordLength = 0;
@@ -177,7 +192,12 @@
handlePasswordExpirationNotification(getUserData(userHandle));
}
});
- } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ }
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action)
+ || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
+ manageMonitoringCertificateNotification(intent);
+ }
+ if (Intent.ACTION_USER_REMOVED.equals(action)) {
removeUserData(userHandle);
} else if (Intent.ACTION_USER_STARTED.equals(action)
|| Intent.ACTION_PACKAGE_CHANGED.equals(action)
@@ -519,13 +539,20 @@
*/
public DevicePolicyManagerService(Context context) {
mContext = context;
+ mHasFeature = context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_DEVICE_ADMIN);
mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
+ if (!mHasFeature) {
+ // Skip the rest of the initialization
+ return;
+ }
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_STARTED);
+ filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -635,6 +662,14 @@
return mIWindowManager;
}
+ private NotificationManager getNotificationManager() {
+ if (mNotificationManager == null) {
+ mNotificationManager =
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+ return mNotificationManager;
+ }
+
ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
if (admin != null
@@ -738,6 +773,9 @@
}
public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
enforceCrossUserPermission(userHandle);
Intent resolveIntent = new Intent();
resolveIntent.setComponent(adminName);
@@ -1027,6 +1065,9 @@
}
public void systemReady() {
+ if (!mHasFeature) {
+ return;
+ }
synchronized (this) {
loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
loadDeviceOwner();
@@ -1053,11 +1094,71 @@
}
}
+ private void manageMonitoringCertificateNotification(Intent intent) {
+ final NotificationManager notificationManager = getNotificationManager();
+
+ final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
+ if (! hasCert) {
+ if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ for (UserInfo user : um.getUsers()) {
+ notificationManager.cancelAsUser(
+ null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
+ }
+ }
+ return;
+ }
+ final boolean isManaged = getDeviceOwner() != null;
+ int smallIconId;
+ String contentText;
+ if (isManaged) {
+ contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
+ getDeviceOwnerName());
+ smallIconId = R.drawable.stat_sys_certificate_info;
+ } else {
+ contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown);
+ smallIconId = android.R.drawable.stat_sys_warning;
+ }
+
+ Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
+ dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ dialogIntent.setPackage("com.android.settings");
+ // Notification will be sent individually to all users. The activity should start as
+ // whichever user is current when it starts.
+ PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0, dialogIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT);
+
+ Notification noti = new Notification.Builder(mContext)
+ .setSmallIcon(smallIconId)
+ .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning))
+ .setContentText(contentText)
+ .setContentIntent(notifyIntent)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setShowWhen(false)
+ .build();
+
+ // If this is a boot intent, this will fire for each user. But if this is a storage changed
+ // intent, it will fire once, so we need to notify all users.
+ if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ for (UserInfo user : um.getUsers()) {
+ notificationManager.notifyAsUser(
+ null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
+ }
+ } else {
+ notificationManager.notifyAsUser(
+ null, MONITORING_CERT_NOTIFICATION_ID, noti, UserHandle.CURRENT);
+ }
+ }
+
/**
* @param adminReceiver The admin to add
* @param refreshing true = update an active admin, no error
*/
public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
enforceCrossUserPermission(userHandle);
@@ -1101,6 +1202,9 @@
}
public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
@@ -1108,6 +1212,9 @@
}
public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
@@ -1118,7 +1225,12 @@
}
}
+ @SuppressWarnings("unchecked")
public List<ComponentName> getActiveAdmins(int userHandle) {
+ if (!mHasFeature) {
+ return Collections.EMPTY_LIST;
+ }
+
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1135,6 +1247,9 @@
}
public boolean packageHasActiveAdmins(String packageName, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1149,6 +1264,9 @@
}
public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
@@ -1174,6 +1292,9 @@
}
public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
validateQualityConstant(quality);
enforceCrossUserPermission(userHandle);
@@ -1191,6 +1312,9 @@
}
public int getPasswordQuality(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -1213,6 +1337,9 @@
}
public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1228,6 +1355,9 @@
}
public int getPasswordMinimumLength(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1250,6 +1380,9 @@
}
public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1265,6 +1398,9 @@
}
public int getPasswordHistoryLength(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1287,6 +1423,9 @@
}
public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1317,6 +1456,9 @@
* Returns 0 if not configured.
*/
public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0L;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who != null) {
@@ -1362,6 +1504,9 @@
}
public long getPasswordExpiration(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0L;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
return getPasswordExpirationLocked(who, userHandle);
@@ -1369,6 +1514,9 @@
}
public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1384,6 +1532,9 @@
}
public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1421,6 +1572,9 @@
}
public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1443,6 +1597,9 @@
}
public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1458,6 +1615,9 @@
}
public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1480,6 +1640,9 @@
}
public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1495,6 +1658,9 @@
}
public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1517,6 +1683,9 @@
}
public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1532,6 +1701,9 @@
}
public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1554,6 +1726,9 @@
}
public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1569,6 +1744,9 @@
}
public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
@@ -1591,6 +1769,9 @@
}
public boolean isActivePasswordSufficient(int userHandle) {
+ if (!mHasFeature) {
+ return true;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1626,6 +1807,9 @@
}
public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
@@ -1642,6 +1826,9 @@
}
public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
@@ -1667,6 +1854,9 @@
}
public boolean resetPassword(String password, int flags, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
int quality;
synchronized (this) {
@@ -1788,6 +1978,9 @@
}
public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -1833,6 +2026,9 @@
}
public long getMaximumTimeToLock(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
long time = 0;
@@ -1858,6 +2054,9 @@
}
public void lockNow() {
+ if (!mHasFeature) {
+ return;
+ }
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
@@ -1978,6 +2177,9 @@
}
public void wipeData(int flags, final int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
@@ -2013,6 +2215,9 @@
}
public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
@@ -2043,6 +2248,9 @@
public void setActivePasswordState(int quality, int length, int letters, int uppercase,
int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
@@ -2109,12 +2317,14 @@
try {
policy.mFailedPasswordAttempts++;
saveSettingsLocked(userHandle);
- int max = getMaximumFailedPasswordsForWipe(null, userHandle);
- if (max > 0 && policy.mFailedPasswordAttempts >= max) {
- wipeDeviceOrUserLocked(0, userHandle);
+ if (mHasFeature) {
+ int max = getMaximumFailedPasswordsForWipe(null, userHandle);
+ if (max > 0 && policy.mFailedPasswordAttempts >= max) {
+ wipeDeviceOrUserLocked(0, userHandle);
+ }
+ sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
}
- sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
- DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2134,8 +2344,10 @@
policy.mFailedPasswordAttempts = 0;
policy.mPasswordOwner = -1;
saveSettingsLocked(userHandle);
- sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
- DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
+ if (mHasFeature) {
+ sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
+ DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2145,6 +2357,9 @@
public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
String exclusionList, int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
enforceCrossUserPermission(userHandle);
synchronized(this) {
if (who == null) {
@@ -2195,6 +2410,9 @@
}
public ComponentName getGlobalProxyAdmin(int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
enforceCrossUserPermission(userHandle);
synchronized(this) {
DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
@@ -2256,6 +2474,9 @@
* status (for all admins).
*/
public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
+ if (!mHasFeature) {
+ return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
// Check for permissions
@@ -2307,6 +2528,9 @@
* active admins.
*/
public boolean getStorageEncryption(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
// Check for permissions if a particular caller is specified
@@ -2333,6 +2557,9 @@
* Get the current encryption status of the device.
*/
public int getStorageEncryptionStatus(int userHandle) {
+ if (!mHasFeature) {
+ // Ok to return current status.
+ }
enforceCrossUserPermission(userHandle);
return getEncryptionStatus();
}
@@ -2381,6 +2608,9 @@
* Disables all device cameras according to the specified admin.
*/
public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -2401,6 +2631,9 @@
* active admins.
*/
public boolean getCameraDisabled(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return false;
+ }
synchronized (this) {
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
@@ -2424,6 +2657,9 @@
* Selectively disable keyguard features.
*/
public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
@@ -2444,6 +2680,9 @@
* or the aggregate of all active admins if who is null.
*/
public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return 0;
+ }
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who != null) {
@@ -2465,6 +2704,9 @@
@Override
public boolean setDeviceOwner(String packageName, String ownerName) {
+ if (!mHasFeature) {
+ return false;
+ }
if (packageName == null
|| !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
throw new IllegalArgumentException("Invalid package name " + packageName
@@ -2485,6 +2727,9 @@
@Override
public boolean isDeviceOwner(String packageName) {
+ if (!mHasFeature) {
+ return false;
+ }
synchronized (this) {
return mDeviceOwner != null
&& mDeviceOwner.getPackageName().equals(packageName);
@@ -2493,6 +2738,9 @@
@Override
public String getDeviceOwner() {
+ if (!mHasFeature) {
+ return null;
+ }
synchronized (this) {
if (mDeviceOwner != null) {
return mDeviceOwner.getPackageName();
@@ -2503,6 +2751,9 @@
@Override
public String getDeviceOwnerName() {
+ if (!mHasFeature) {
+ return null;
+ }
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
synchronized (this) {
if (mDeviceOwner != null) {
diff --git a/services/java/com/android/server/IdleMaintenanceService.java b/services/java/com/android/server/IdleMaintenanceService.java
index 584d4bc..b0a1aca 100644
--- a/services/java/com/android/server/IdleMaintenanceService.java
+++ b/services/java/com/android/server/IdleMaintenanceService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.Activity;
+import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -24,12 +25,13 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
-import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Slog;
/**
* This service observes the device state and when applicable sends
@@ -69,6 +71,9 @@
private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE =
"com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE";
+ private static final String ACTION_FORCE_IDLE_MAINTENANCE =
+ "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE";
+
private static final Intent sIdleMaintenanceStartIntent;
static {
sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START);
@@ -115,10 +120,10 @@
mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
- register(mContext.getMainLooper());
+ register(mHandler);
}
- public void register(Looper looper) {
+ public void register(Handler handler) {
IntentFilter intentFilter = new IntentFilter();
// Alarm actions.
@@ -136,7 +141,12 @@
intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
mContext.registerReceiverAsUser(this, UserHandle.ALL,
- intentFilter, null, new Handler(looper));
+ intentFilter, null, mHandler);
+
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_FORCE_IDLE_MAINTENANCE);
+ mContext.registerReceiverAsUser(this, UserHandle.ALL,
+ intentFilter, android.Manifest.permission.SET_ACTIVITY_WATCHER, mHandler);
}
private void scheduleUpdateIdleMaintenanceState(long delayMillis) {
@@ -149,7 +159,7 @@
mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
}
- private void updateIdleMaintenanceState() {
+ private void updateIdleMaintenanceState(boolean noisy) {
if (mIdleMaintenanceStarted) {
// Idle maintenance can be interrupted by user activity, or duration
// time out, or low battery.
@@ -170,9 +180,9 @@
getNextIdleMaintenanceIntervalStartFromNow());
}
}
- } else if (deviceStatePermitsIdleMaintenanceStart()
- && lastUserActivityPermitsIdleMaintenanceStart()
- && lastRunPermitsIdleMaintenanceStart()) {
+ } else if (deviceStatePermitsIdleMaintenanceStart(noisy)
+ && lastUserActivityPermitsIdleMaintenanceStart(noisy)
+ && lastRunPermitsIdleMaintenanceStart(noisy)) {
// Now that we started idle maintenance, we should schedule another
// update for the moment when the idle maintenance times out.
scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION);
@@ -182,8 +192,8 @@
isBatteryCharging() ? 1 : 0);
mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
sendIdleMaintenanceStartIntent();
- } else if (lastUserActivityPermitsIdleMaintenanceStart()) {
- if (lastRunPermitsIdleMaintenanceStart()) {
+ } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) {
+ if (lastRunPermitsIdleMaintenanceStart(noisy)) {
// The user does not use the device and we did not run maintenance in more
// than the min interval between runs, so schedule an update - maybe the
// battery will be charged latter.
@@ -204,6 +214,10 @@
private void sendIdleMaintenanceStartIntent() {
mWakeLock.acquire();
+ try {
+ ActivityManagerNative.getDefault().performIdleMaintenance();
+ } catch (RemoteException e) {
+ }
mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL,
null, this, mHandler, Activity.RESULT_OK, null, null);
}
@@ -214,25 +228,37 @@
null, this, mHandler, Activity.RESULT_OK, null, null);
}
- private boolean deviceStatePermitsIdleMaintenanceStart() {
+ private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) {
final int minBatteryLevel = isBatteryCharging()
? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
: MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING;
- return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+ boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
&& mBatteryService.getBatteryLevel() > minBatteryLevel);
+ if (!allowed && noisy) {
+ Slog.i("IdleMaintenance", "Idle maintenance not allowed due to power");
+ }
+ return allowed;
}
- private boolean lastUserActivityPermitsIdleMaintenanceStart() {
+ private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) {
// The last time the user poked the device is above the threshold.
- return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+ boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
&& SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis
> MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
+ if (!allowed && noisy) {
+ Slog.i("IdleMaintenance", "Idle maintenance not allowed due to last user activity");
+ }
+ return allowed;
}
- private boolean lastRunPermitsIdleMaintenanceStart() {
+ private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) {
// Enough time passed since the last maintenance run.
- return SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
+ boolean allowed = SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
> MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
+ if (!allowed && noisy) {
+ Slog.i("IdleMaintenance", "Idle maintenance not allowed due time since last");
+ }
+ return allowed;
}
private boolean lastUserActivityPermitsIdleMaintenanceRunning() {
@@ -266,7 +292,7 @@
// next release. The only client for this for now is internal an holds
// a wake lock correctly.
if (mIdleMaintenanceStarted) {
- updateIdleMaintenanceState();
+ updateIdleMaintenanceState(false);
}
} else if (Intent.ACTION_SCREEN_ON.equals(action)
|| Intent.ACTION_DREAMING_STOPPED.equals(action)) {
@@ -276,7 +302,7 @@
unscheduleUpdateIdleMaintenanceState();
// If the screen went on/stopped dreaming, we know the user is using the
// device which means that idle maintenance should be stopped if running.
- updateIdleMaintenanceState();
+ updateIdleMaintenanceState(false);
} else if (Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_DREAMING_STARTED.equals(action)) {
mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
@@ -285,7 +311,12 @@
// this timeout elapses since the device may go to sleep by then.
scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
} else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) {
- updateIdleMaintenanceState();
+ updateIdleMaintenanceState(false);
+ } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) {
+ long now = SystemClock.elapsedRealtime() - 1;
+ mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START;
+ mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
+ updateIdleMaintenanceState(true);
} else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)
|| Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
// We were holding a wake lock while broadcasting the idle maintenance
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d38756f..ef50df7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -217,8 +217,7 @@
ServiceManager.addService("telephony.registry", telephonyRegistry);
Slog.i(TAG, "Scheduling Policy");
- ServiceManager.addService(Context.SCHEDULING_POLICY_SERVICE,
- new SchedulingPolicyService());
+ ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
AttributeCache.init(context);
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index b75eab4..37fbb13 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -299,11 +299,17 @@
boolean addToStarting = false;
if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid);
- if (proc == null || proc.curProcState >= ActivityManager.PROCESS_STATE_RECEIVER) {
+ if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
// If this is not coming from a foreground caller, then we may want
// to delay the start if there are already other background services
// that are starting. This is to avoid process start spam when lots
// of applications are all handling things like connectivity broadcasts.
+ // We only do this for cached processes, because otherwise an application
+ // can have assumptions about calling startService() for a service to run
+ // in its own process, and for that process to not be killed before the
+ // service is started. This is especially the case for receivers, which
+ // may start a service in onReceive() to do some additional work and have
+ // initialized some global state as part of that.
if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Potential start delay of " + r + " in "
+ proc);
if (r.delayed) {
@@ -324,7 +330,7 @@
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are
- // currently running other services.
+ // currently running other services or receivers.
addToStarting = true;
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STATS) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e208f10..80f4b00 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -172,7 +172,6 @@
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
@@ -850,10 +849,39 @@
int mNewNumServiceProcs = 0;
/**
- * System monitoring: number of processes that died since the last
- * N procs were started.
+ * Allow the current computed overall memory level of the system to go down?
+ * This is set to false when we are killing processes for reasons other than
+ * memory management, so that the now smaller process list will not be taken as
+ * an indication that memory is tighter.
*/
- int[] mProcDeaths = new int[20];
+ boolean mAllowLowerMemLevel = false;
+
+ /**
+ * The last computed memory level, for holding when we are in a state that
+ * processes are going away for other reasons.
+ */
+ int mLastMemoryLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+
+ /**
+ * The last total number of process we have, to determine if changes actually look
+ * like a shrinking number of process due to lower RAM.
+ */
+ int mLastNumProcesses;
+
+ /**
+ * The uptime of the last time we performed idle maintenance.
+ */
+ long mLastIdleTime = SystemClock.uptimeMillis();
+
+ /**
+ * Total time spent with RAM that has been added in the past since the last idle time.
+ */
+ long mLowRamTimeSinceLastIdle = 0;
+
+ /**
+ * If RAM is currently low, when that horrible situatin started.
+ */
+ long mLowRamStartTime = 0;
/**
* This is set if we had to do a delayed dexopt of an app before launching
@@ -978,17 +1006,18 @@
static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26;
static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
- static final int CLEAR_DNS_CACHE = 28;
- static final int UPDATE_HTTP_PROXY = 29;
+ static final int CLEAR_DNS_CACHE_MSG = 28;
+ static final int UPDATE_HTTP_PROXY_MSG = 29;
static final int SHOW_COMPAT_MODE_DIALOG_MSG = 30;
static final int DISPATCH_PROCESSES_CHANGED = 31;
static final int DISPATCH_PROCESS_DIED = 32;
- static final int REPORT_MEM_USAGE = 33;
+ static final int REPORT_MEM_USAGE_MSG = 33;
static final int REPORT_USER_SWITCH_MSG = 34;
static final int CONTINUE_USER_SWITCH_MSG = 35;
static final int USER_SWITCH_TIMEOUT_MSG = 36;
static final int IMMERSIVE_MODE_LOCK_MSG = 37;
- static final int PERSIST_URI_GRANTS = 38;
+ static final int PERSIST_URI_GRANTS_MSG = 38;
+ static final int REQUEST_ALL_PSS_MSG = 39;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1169,7 +1198,7 @@
}
}
} break;
- case CLEAR_DNS_CACHE: {
+ case CLEAR_DNS_CACHE_MSG: {
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
@@ -1183,7 +1212,7 @@
}
}
} break;
- case UPDATE_HTTP_PROXY: {
+ case UPDATE_HTTP_PROXY_MSG: {
ProxyProperties proxy = (ProxyProperties)msg.obj;
String host = "";
String port = "";
@@ -1369,7 +1398,7 @@
dispatchProcessDied(pid, uid);
break;
}
- case REPORT_MEM_USAGE: {
+ case REPORT_MEM_USAGE_MSG: {
final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
Thread thread = new Thread() {
@Override public void run() {
@@ -1583,10 +1612,14 @@
}
break;
}
- case PERSIST_URI_GRANTS: {
+ case PERSIST_URI_GRANTS_MSG: {
writeGrantedUriPermissions();
break;
}
+ case REQUEST_ALL_PSS_MSG: {
+ requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
+ break;
+ }
}
}
};
@@ -1630,6 +1663,10 @@
num++;
proc.lastPssTime = SystemClock.uptimeMillis();
proc.baseProcessTracker.addPss(pss, tmp[0], true);
+ if (proc.initialIdlePss == 0) {
+ proc.initialIdlePss = pss;
+ }
+ proc.lastPss = pss;
}
}
}
@@ -2250,8 +2287,7 @@
}
}
- final void updateLruProcessLocked(ProcessRecord app,
- boolean oomAdj) {
+ final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj) {
mLruSeq++;
updateLruProcessInternalLocked(app, 0);
@@ -2417,9 +2453,6 @@
updateCpuStats();
- System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
- mProcDeaths[0] = 0;
-
try {
int uid = app.uid;
@@ -3428,7 +3461,7 @@
}
}
if (doReport) {
- Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE, memInfos);
+ Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos);
mHandler.sendMessage(msg);
}
scheduleAppGcsLocked();
@@ -3438,8 +3471,6 @@
final void appDiedLocked(ProcessRecord app, int pid,
IApplicationThread thread) {
- mProcDeaths[0]++;
-
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
stats.noteProcessDiedLocked(app.info.uid, pid);
@@ -3448,17 +3479,27 @@
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
- if (!app.killedBackground) {
+ boolean doLowMem = app.instrumentationClass == null;
+ boolean doOomAdj = doLowMem;
+ if (!app.killedByAm) {
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died.");
+ mAllowLowerMemLevel = true;
+ } else {
+ // Note that we always want to do oom adj to update our state with the
+ // new number of procs.
+ mAllowLowerMemLevel = false;
+ doLowMem = false;
}
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
if (DEBUG_CLEANUP) Slog.v(
TAG, "Dying app: " + app + ", pid: " + pid
+ ", thread: " + thread.asBinder());
- boolean doLowMem = app.instrumentationClass == null;
handleAppDiedLocked(app, false, true);
+ if (doOomAdj) {
+ updateOomAdjLocked();
+ }
if (doLowMem) {
doLowMemReportIfNeededLocked(app);
}
@@ -3791,10 +3832,7 @@
synchronized (this) {
if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
- Slog.w(TAG, "Killing " + app + ": background ANR");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "background ANR");
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "background ANR");
return;
}
@@ -3979,6 +4017,7 @@
for (int i=0; i<N; i++) {
removeProcessLocked(procs.get(i), false, true, "kill all background");
}
+ mAllowLowerMemLevel = true;
updateOomAdjLocked();
doLowMemReportIfNeededLocked(null);
}
@@ -4478,10 +4517,9 @@
mPidsSelfLocked.remove(pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
- Slog.i(TAG, "Killing proc " + app.toShortString() + ": " + reason);
+ killUnneededProcessLocked(app, reason);
handleAppDiedLocked(app, true, allowRestart);
mLruProcesses.remove(app);
- Process.killProcessQuiet(pid);
if (app.persistent && !app.isolated) {
if (!callerWillRestart) {
@@ -4523,9 +4561,7 @@
checkAppInLaunchingProvidersLocked(app, true);
// Take care of any services that are waiting for the process.
mServices.processStartTimedOutLocked(app);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, pid,
- app.processName, app.setAdj, "start timeout");
- Process.killProcessQuiet(pid);
+ killUnneededProcessLocked(app, "start timeout");
if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
Slog.w(TAG, "Unattached app died before backup, skipping");
try {
@@ -5769,8 +5805,8 @@
pi.packageName, targetPkg, targetUid, uri);
final boolean persistChanged = perm.grantModes(modeFlags, persist, owner);
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS);
- mHandler.obtainMessage(PERSIST_URI_GRANTS).sendToTarget();
+ mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
+ mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
}
}
@@ -5994,8 +6030,8 @@
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS);
- mHandler.obtainMessage(PERSIST_URI_GRANTS).sendToTarget();
+ mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
+ mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
}
}
@@ -6079,8 +6115,8 @@
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS);
- mHandler.obtainMessage(PERSIST_URI_GRANTS).sendToTarget();
+ mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
+ mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
}
}
@@ -6508,6 +6544,16 @@
}
}
+ private void killUnneededProcessLocked(ProcessRecord pr, String reason) {
+ if (!pr.killedByAm) {
+ Slog.i(TAG, "Killing " + pr.toShortString() + " (adj " + pr.setAdj + "): " + reason);
+ EventLog.writeEvent(EventLogTags.AM_KILL, pr.userId, pr.pid,
+ pr.processName, pr.setAdj, reason);
+ pr.killedByAm = true;
+ Process.killProcessQuiet(pr.pid);
+ }
+ }
+
private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) {
mRecentTasks.remove(tr);
mStackSupervisor.removeTask(tr);
@@ -6546,11 +6592,7 @@
for (int i=0; i<procs.size(); i++) {
ProcessRecord pr = procs.get(i);
if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + pr.toShortString() + ": remove task");
- EventLog.writeEvent(EventLogTags.AM_KILL, pr.userId, pr.pid,
- pr.processName, pr.setAdj, "remove task");
- pr.killedBackground = true;
- Process.killProcessQuiet(pr.pid);
+ killUnneededProcessLocked(pr, "remove task");
} else {
pr.waitingToKill = "remove task";
}
@@ -8401,13 +8443,9 @@
continue;
}
int adj = proc.setAdj;
- if (adj >= worstType && !proc.killedBackground) {
- Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
- EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId, proc.pid,
- proc.processName, adj, reason);
+ if (adj >= worstType && !proc.killedByAm) {
+ killUnneededProcessLocked(proc, reason);
killed = true;
- proc.killedBackground = true;
- Process.killProcessQuiet(pids[i]);
}
}
}
@@ -8449,13 +8487,9 @@
if (proc == null) continue;
final int adj = proc.setAdj;
- if (adj > belowAdj && !proc.killedBackground) {
- Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
- EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId,
- proc.pid, proc.processName, adj, reason);
+ if (adj > belowAdj && !proc.killedByAm) {
+ killUnneededProcessLocked(proc, reason);
killed = true;
- proc.killedBackground = true;
- Process.killProcessQuiet(pid);
}
}
}
@@ -8533,6 +8567,61 @@
br.onReceive(mContext, intent);
}
+ private long getLowRamTimeSinceIdle(long now) {
+ return mLowRamTimeSinceLastIdle + (mLowRamStartTime > 0 ? (now-mLowRamStartTime) : 0);
+ }
+
+ @Override
+ public void performIdleMaintenance() {
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
+ synchronized (this) {
+ final long now = SystemClock.uptimeMillis();
+ final long timeSinceLastIdle = now - mLastIdleTime;
+ final long lowRamSinceLastIdle = getLowRamTimeSinceIdle(now);
+ mLastIdleTime = now;
+ mLowRamTimeSinceLastIdle = 0;
+ if (mLowRamStartTime != 0) {
+ mLowRamStartTime = now;
+ }
+
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Idle maintenance over ");
+ TimeUtils.formatDuration(timeSinceLastIdle, sb);
+ sb.append(" low RAM for ");
+ TimeUtils.formatDuration(lowRamSinceLastIdle, sb);
+ Slog.i(TAG, sb.toString());
+
+ // If at least 1/3 of our time since the last idle period has been spent
+ // with RAM low, then we want to kill processes.
+ boolean doKilling = lowRamSinceLastIdle > (timeSinceLastIdle/3);
+
+ for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+ ProcessRecord proc = mLruProcesses.get(i);
+ if (proc.notCachedSinceIdle) {
+ if (proc.setProcState > ActivityManager.PROCESS_STATE_TOP
+ && proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
+ if (doKilling && proc.initialIdlePss != 0
+ && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
+ killUnneededProcessLocked(proc, "idle maint (pss " + proc.lastPss
+ + " from " + proc.initialIdlePss + ")");
+ }
+ }
+ } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME) {
+ proc.notCachedSinceIdle = true;
+ proc.initialIdlePss = 0;
+ }
+ }
+
+ mHandler.removeMessages(REQUEST_ALL_PSS_MSG);
+ mHandler.sendEmptyMessageDelayed(REQUEST_ALL_PSS_MSG, 2*60*1000);
+ }
+ }
+
public final void startRunning(String pkg, String cls, String action,
String data) {
synchronized(this) {
@@ -8967,10 +9056,7 @@
}
if (app.pid > 0 && app.pid != MY_PID) {
handleAppCrashLocked(app);
- Slog.i(ActivityManagerService.TAG, "Killing " + app + ": user's request");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "user's request after error");
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "user request after error");
}
}
}
@@ -10444,6 +10530,15 @@
+ " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs
+ " mNumServiceProcs=" + mNumServiceProcs
+ " mNewNumServiceProcs=" + mNewNumServiceProcs);
+ pw.println(" mAllowLowerMemLevel=" + mAllowLowerMemLevel
+ + " mLastMemoryLevel" + mLastMemoryLevel
+ + " mLastNumProcesses" + mLastNumProcesses);
+ long now = SystemClock.uptimeMillis();
+ pw.print(" mLastIdleTime=");
+ TimeUtils.formatDuration(now, mLastIdleTime, pw);
+ pw.print(" mLowRamSinceLastIdle=");
+ TimeUtils.formatDuration(getLowRamTimeSinceIdle(now), pw);
+ pw.println();
}
}
@@ -11704,13 +11799,9 @@
if (!capp.persistent && capp.thread != null
&& capp.pid != 0
&& capp.pid != MY_PID) {
- Slog.i(TAG, "Kill " + capp.processName
- + " (pid " + capp.pid + "): provider " + cpr.info.name
- + " in dying process " + (proc != null ? proc.processName : "??"));
- EventLog.writeEvent(EventLogTags.AM_KILL, capp.userId, capp.pid,
- capp.processName, capp.setAdj, "dying provider "
- + cpr.name.toShortString());
- Process.killProcessQuiet(capp.pid);
+ killUnneededProcessLocked(capp, "depends on provider "
+ + cpr.name.flattenToShortString()
+ + " in dying proc " + (proc != null ? proc.processName : "??"));
}
} else if (capp.thread != null && conn.provider.provider != null) {
try {
@@ -12791,12 +12882,12 @@
}
if (intent.ACTION_CLEAR_DNS_CACHE.equals(intent.getAction())) {
- mHandler.sendEmptyMessage(CLEAR_DNS_CACHE);
+ mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
}
if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
ProxyProperties proxy = intent.getParcelableExtra("proxy");
- mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY, proxy));
+ mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
}
// Add to the sticky list if requested.
@@ -14527,26 +14618,18 @@
stats.reportExcessiveWakeLocked(app.info.uid, app.processName,
realtimeSince, wtimeUsed);
}
- Slog.w(TAG, "Excessive wake lock in " + app.processName
- + " (pid " + app.pid + "): held " + wtimeUsed
+ killUnneededProcessLocked(app, "excessive wake held " + wtimeUsed
+ " during " + realtimeSince);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "excessive wake lock");
app.baseProcessTracker.reportExcessiveWake(app.pkgList);
- Process.killProcessQuiet(app.pid);
} else if (doCpuKills && uptimeSince > 0
&& ((cputimeUsed*100)/uptimeSince) >= 50) {
synchronized (stats) {
stats.reportExcessiveCpuLocked(app.info.uid, app.processName,
uptimeSince, cputimeUsed);
}
- Slog.w(TAG, "Excessive CPU in " + app.processName
- + " (pid " + app.pid + "): used " + cputimeUsed
+ killUnneededProcessLocked(app, "excessive cpu " + cputimeUsed
+ " during " + uptimeSince);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "excessive cpu");
app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
- Process.killProcessQuiet(app.pid);
} else {
app.lastWakeTime = wtime;
app.lastCpuTime = app.curCpuTime;
@@ -14593,11 +14676,7 @@
+ " to " + app.curSchedGroup);
if (app.waitingToKill != null &&
app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, app.waitingToKill);
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, app.waitingToKill);
success = false;
} else {
if (true) {
@@ -14657,6 +14736,9 @@
"Proc state change of " + app.processName
+ " to " + app.curProcState);
app.setProcState = app.curProcState;
+ if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
+ app.notCachedSinceIdle = false;
+ }
if (!doingAll) {
setProcessTrackerState(app, mProcessStats.getMemFactorLocked(), now);
} else {
@@ -14667,7 +14749,7 @@
}
private final void setProcessTrackerState(ProcessRecord proc, int memFactor, long now) {
- if (proc.thread != null) {
+ if (proc.thread != null && proc.baseProcessTracker != null) {
proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
}
}
@@ -14783,7 +14865,7 @@
int nextEmptyAdj = curEmptyAdj+2;
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
- if (!app.killedBackground && app.thread != null) {
+ if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
final boolean wasKeeping = app.keeping;
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
@@ -14858,34 +14940,19 @@
mNumCachedHiddenProcs++;
numCached++;
if (numCached > cachedProcessLimit) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): cached #" + numCached);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "cached #" + numCached);
}
break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
if (numEmpty > ProcessList.TRIM_EMPTY_APPS
&& app.lastActivityTime < oldTime) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): empty for "
- + ((oldTime+ProcessList.MAX_EMPTY_TIME-app.lastActivityTime)
- / 1000) + "s");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "old background process");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "empty for "
+ + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
+ / 1000) + "s");
} else {
numEmpty++;
if (numEmpty > emptyProcessLimit) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): empty #" + numEmpty);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "empty #" + numEmpty);
}
}
break;
@@ -14901,16 +14968,11 @@
// definition not re-use the same process again, and it is
// good to avoid having whatever code was running in them
// left sitting around after no longer needed.
- Slog.i(TAG, "Isolated process " + app.processName
- + " (pid " + app.pid + ") no longer needed");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "isolated not needed");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "isolated not needed");
}
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
- && !app.killedBackground) {
+ && !app.killedByAm) {
numTrimming++;
}
}
@@ -14924,31 +14986,60 @@
// are managing to keep around is less than half the maximum we desire;
// if we are keeping a good number around, we'll let them use whatever
// memory they want.
- boolean allChanged;
+ final int numCachedAndEmpty = numCached + numEmpty;
+ int memFactor;
if (numCached <= ProcessList.TRIM_CACHED_APPS
&& numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
- final int numCachedAndEmpty = numCached + numEmpty;
+ if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
+ } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
+ } else {
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
+ }
+ } else {
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+ }
+ // We always allow the memory level to go up (better). We only allow it to go
+ // down if we are in a state where that is allowed, *and* the total number of processes
+ // has gone down since last time.
+ if (DEBUG_OOM_ADJ) Slog.d(TAG, "oom: memFactor=" + memFactor + " last=" + mLastMemoryLevel
+ + " allowLow=" + mAllowLowerMemLevel + " numProcs=" + mLruProcesses.size()
+ + " last=" + mLastNumProcesses);
+ if (memFactor > mLastMemoryLevel) {
+ if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
+ memFactor = mLastMemoryLevel;
+ if (DEBUG_OOM_ADJ) Slog.d(TAG, "Keeping last mem factor!");
+ }
+ }
+ mLastMemoryLevel = memFactor;
+ mLastNumProcesses = mLruProcesses.size();
+ boolean allChanged = mProcessStats.setMemFactorLocked(
+ ProcessStats.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
+ final int trackerMemFactor = mProcessStats.getMemFactorLocked();
+ if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
+ if (mLowRamStartTime == 0) {
+ mLowRamStartTime = now;
+ }
+ int step = 0;
+ int fgTrimLevel;
+ switch (memFactor) {
+ case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+ fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+ break;
+ case ProcessStats.ADJ_MEM_FACTOR_LOW:
+ fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
+ break;
+ default:
+ fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
+ break;
+ }
int factor = numTrimming/3;
int minFactor = 2;
if (mHomeProcess != null) minFactor++;
if (mPreviousProcess != null) minFactor++;
if (factor < minFactor) factor = minFactor;
- int step = 0;
- int fgTrimLevel;
- int memFactor;
- if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
- fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
- memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
- } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
- fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
- memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
- } else {
- fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
- memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
- }
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
- allChanged = mProcessStats.setMemFactorLocked(memFactor, !mSleeping, now);
- final int trackerMemFactor = mProcessStats.getMemFactorLocked();
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
@@ -14956,7 +15047,7 @@
app.procStateChanged = false;
}
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
- && !app.killedBackground) {
+ && !app.killedByAm) {
if (app.trimMemoryLevel < curLevel && app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
@@ -15036,9 +15127,10 @@
}
}
} else {
- allChanged = mProcessStats.setMemFactorLocked(
- ProcessStats.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
- final int trackerMemFactor = mProcessStats.getMemFactorLocked();
+ if (mLowRamStartTime != 0) {
+ mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
+ mLowRamStartTime = 0;
+ }
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
@@ -15107,6 +15199,7 @@
if (app.pid > 0 && app.pid != MY_PID) {
EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "empty");
+ app.killedByAm = true;
Process.killProcessQuiet(app.pid);
} else {
try {
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index e0eb2c4..7756ff9 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1417,7 +1417,8 @@
final ActivityStack lastStack = getLastStack();
ActivityRecord curTop = lastStack == null?
null : lastStack.topRunningNonDelayedActivityLocked(notTop);
- if (curTop != null && curTop.task != intentActivity.task) {
+ if (curTop != null && (curTop.task != intentActivity.task ||
+ curTop.task != lastStack.topTask())) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (sourceRecord == null || (sourceStack.topActivity() != null &&
sourceStack.topActivity().task == sourceRecord.task)) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 35e06b6..d230779 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -66,6 +66,8 @@
long lastPssTime; // Last time we retrieved PSS data
long nextPssTime; // Next time we want to request PSS data
long lastStateTime; // Last time setProcState changed
+ long initialIdlePss; // Initial memory pss of process for idle maintenance.
+ long lastPss; // Last computed memory pss.
int maxAdj; // Maximum OOM adjustment for this process
int curRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
@@ -82,6 +84,7 @@
boolean serviceb; // Process currently is on the service B list
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
+ boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
boolean hasActivities; // Are there any activities running in this process?
boolean hasClientActivities; // Are there any client services with activities?
boolean hasStartedServices; // Are there any started services running in this process?
@@ -92,7 +95,7 @@
boolean pendingUiClean; // Want to clean up resources from showing UI?
boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower
boolean bad; // True if disabled in the bad process list
- boolean killedBackground; // True when proc has been killed due to too many bg
+ boolean killedByAm; // True when proc has been killed by activity manager, not for RAM
boolean procStateChanged; // Keep track of whether we changed 'setAdj'.
String waitingToKill; // Process is waiting to be killed when in the bg; reason
IBinder forcingToForeground;// Token that is forcing this process to be foreground
@@ -216,6 +219,11 @@
pw.print(" keeping="); pw.print(keeping);
pw.print(" cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
+ if (notCachedSinceIdle) {
+ pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle);
+ pw.print(" initialIdlePss="); pw.print(initialIdlePss);
+ pw.print(" lastPss="); pw.println(lastPss);
+ }
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
pw.print(" curRaw="); pw.print(curRawAdj);
pw.print(" setRaw="); pw.print(setRawAdj);
@@ -280,8 +288,8 @@
pw.print(" lastLowMemory=");
TimeUtils.formatDuration(lastLowMemory, now, pw);
pw.print(" reportLowMemory="); pw.println(reportLowMemory);
- if (killedBackground || waitingToKill != null) {
- pw.print(prefix); pw.print("killedBackground="); pw.print(killedBackground);
+ if (killedByAm || waitingToKill != null) {
+ pw.print(prefix); pw.print("killedByAm="); pw.print(killedByAm);
pw.print(" waitingToKill="); pw.println(waitingToKill);
}
if (debugging || crashing || crashDialog != null || notResponding
@@ -559,7 +567,8 @@
*/
public boolean addPackage(String pkg, ProcessStatsService tracker) {
if (!pkgList.containsKey(pkg)) {
- pkgList.put(pkg, tracker.getProcessStateLocked(pkg, info.uid, processName));
+ pkgList.put(pkg, baseProcessTracker != null
+ ? tracker.getProcessStateLocked(pkg, info.uid, processName) : null);
return true;
}
return false;
@@ -584,25 +593,30 @@
* Delete all packages from list except the package indicated in info
*/
public void resetPackageList(ProcessStatsService tracker) {
- long now = SystemClock.uptimeMillis();
- baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), now, pkgList);
final int N = pkgList.size();
- if (N != 1) {
- for (int i=0; i<N; i++) {
- ProcessStats.ProcessState ps = pkgList.valueAt(i);
- if (ps != null && ps != baseProcessTracker) {
- ps.makeInactive();
- }
+ if (baseProcessTracker != null) {
+ long now = SystemClock.uptimeMillis();
+ baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), now, pkgList);
+ if (N != 1) {
+ for (int i=0; i<N; i++) {
+ ProcessStats.ProcessState ps = pkgList.valueAt(i);
+ if (ps != null && ps != baseProcessTracker) {
+ ps.makeInactive();
+ }
+ }
+ pkgList.clear();
+ ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
+ info.packageName, info.uid, processName);
+ pkgList.put(info.packageName, ps);
+ if (thread != null && ps != baseProcessTracker) {
+ ps.makeActive();
+ }
}
+ } else if (N != 1) {
pkgList.clear();
- ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
- info.packageName, info.uid, processName);
- pkgList.put(info.packageName, ps);
- if (thread != null && ps != baseProcessTracker) {
- ps.makeActive();
- }
+ pkgList.put(info.packageName, null);
}
}
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index c180f6e..582e11e 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -445,7 +445,7 @@
static private void dumpHelp(PrintWriter pw) {
pw.println("Process stats (procstats) dump options:");
pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
- pw.println(" [--details] [--current] [--commit] [--write] [-h] [<package.name>]");
+ pw.println(" [--details] [--current] [--commit] [--reset] [--write] [-h] [<package.name>]");
pw.println(" --checkin: perform a checkin: print and delete old committed states.");
pw.println(" --c: print only state in checkin format.");
pw.println(" --csv: output data suitable for putting in a spreadsheet.");
@@ -456,6 +456,7 @@
pw.println(" --details: dump all execution details, not just summary.");
pw.println(" --current: only dump current state.");
pw.println(" --commit: commit current stats to disk and reset to start new stats.");
+ pw.println(" --reset: reset current stats, without committing.");
pw.println(" --write: write current in-memory stats to disk.");
pw.println(" --read: replace current stats with last-written stats.");
pw.println(" -a: print everything.");
@@ -551,17 +552,29 @@
} else if ("--current".equals(arg)) {
currentOnly = true;
} else if ("--commit".equals(arg)) {
- mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
- writeStateLocked(true, true);
- pw.println("Process stats committed.");
+ synchronized (mAm) {
+ mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
+ writeStateLocked(true, true);
+ pw.println("Process stats committed.");
+ }
+ return;
+ } else if ("--reset".equals(arg)) {
+ synchronized (mAm) {
+ mProcessStats.resetSafely();
+ pw.println("Process stats reset.");
+ }
return;
} else if ("--write".equals(arg)) {
- writeStateSyncLocked();
- pw.println("Process stats written.");
+ synchronized (mAm) {
+ writeStateSyncLocked();
+ pw.println("Process stats written.");
+ }
return;
} else if ("--read".equals(arg)) {
- readLocked(mProcessStats, mFile);
- pw.println("Process stats read.");
+ synchronized (mAm) {
+ readLocked(mProcessStats, mFile);
+ pw.println("Process stats read.");
+ }
return;
} else if ("-h".equals(arg)) {
dumpHelp(pw);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 7cc568e..decda96 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5509,10 +5509,9 @@
// version of the one on the data partition, but which
// granted a new system permission that it didn't have
// before. In this case we do want to allow the app to
- // now get the new permission, because it is allowed by
- // the system image.
- allowed = false;
- if (sysPs.pkg != null) {
+ // now get the new permission if the new system-partition
+ // apk is privileged to get it.
+ if (sysPs.pkg != null && isPrivilegedApp(pkg)) {
for (int j=0;
j<sysPs.pkg.requestedPermissions.size(); j++) {
if (perm.equals(
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 8e0c92a..377c390 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2853,6 +2853,7 @@
ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
+ ApplicationInfo.FLAG_PRIVILEGED, "PRIVILEGED",
ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
};
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
index 926f822..ddc5046 100644
--- a/services/java/com/android/server/print/PrintManagerService.java
+++ b/services/java/com/android/server/print/PrintManagerService.java
@@ -33,8 +33,10 @@
import android.print.IPrintManager;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrinterId;
+import android.printservice.PrintServiceInfo;
import android.provider.Settings;
import android.util.SparseArray;
@@ -69,30 +71,32 @@
BackgroundThread.getHandler().post(new Runnable() {
@Override
public void run() {
+ final UserState userState;
synchronized (mLock) {
- UserState userState = getCurrentUserStateLocked();
+ userState = getCurrentUserStateLocked();
userState.updateIfNeededLocked();
- userState.getSpoolerLocked().start();
}
+ // This is the first time we switch to this user after boot, so
+ // now is the time to remove obsolete print jobs since they
+ // are from the last boot and no application would query them.
+ userState.removeObsoletePrintJobs();
}
});
}
@Override
- public PrintJobInfo print(String printJobName, IPrintClient client,
- IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId,
- int userId) {
+ public PrintJobInfo print(String printJobName, final IPrintClient client,
+ final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
+ int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return spooler.createPrintJob(printJobName, client, documentAdapter,
+ return userState.print(printJobName, client, documentAdapter,
attributes, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -104,89 +108,75 @@
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return spooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY,
- resolvedAppId);
+ return userState.getPrintJobInfos(resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) {
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- return spooler.getPrintJobInfo(printJobId, resolvedAppId);
+ return userState.getPrintJobInfo(printJobId, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public void cancelPrintJob(int printJobId, int appId, int userId) {
+ public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
- final RemotePrintSpooler spooler;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
- spooler = userState.getSpoolerLocked();
}
final long identity = Binder.clearCallingIdentity();
try {
- PrintJobInfo printJobInfo = spooler.getPrintJobInfo(printJobId, resolvedAppId);
- if (printJobInfo == null) {
- return;
- }
- if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
- ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
- RemotePrintService printService = null;
- synchronized (mLock) {
- printService = userState.getActiveServicesLocked().get(printServiceName);
- }
- if (printService == null) {
- return;
- }
- printService.onRequestCancelPrintJob(printJobInfo);
- } else {
- // If the print job is failed we do not need cooperation
- // from the print service.
- spooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null);
- }
+ userState.cancelPrintJob(printJobId, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public void restartPrintJob(int printJobId, int appId, int userId) {
+ public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
- final RemotePrintSpooler spooler;
+ final UserState userState;
synchronized (mLock) {
- spooler = getOrCreateUserStateLocked(resolvedUserId).getSpoolerLocked();
+ userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
- PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, resolvedAppId, resolvedUserId);
- if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
- return;
- }
- spooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
+ userState.restartPrintJob(printJobId, resolvedAppId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userState.getEnabledPrintServices();
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -426,6 +416,7 @@
// user changes
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
@@ -454,15 +445,24 @@
}
private void switchUser(int newUserId) {
+ UserState userState;
synchronized (mLock) {
if (newUserId == mCurrentUserId) {
return;
}
mCurrentUserId = newUserId;
- UserState userState = getCurrentUserStateLocked();
- userState.updateIfNeededLocked();
- userState.getSpoolerLocked().start();
+ userState = mUserStates.get(mCurrentUserId);
+ if (userState == null) {
+ userState = getCurrentUserStateLocked();
+ userState.updateIfNeededLocked();
+ } else {
+ userState.updateIfNeededLocked();
+ }
}
+ // This is the first time we switch to this user after boot, so
+ // now is the time to remove obsolete print jobs since they
+ // are from the last boot and no application would query them.
+ userState.removeObsoletePrintJobs();
}
private void removeUser(int removedUserId) {
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
index f15c760..a20973e 100644
--- a/services/java/com/android/server/print/RemotePrintService.java
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ParceledListSlice;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -29,6 +30,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterId;
@@ -83,6 +85,8 @@
private boolean mHasPrinterDiscoverySession;
+ private boolean mServiceDead;
+
private List<PrinterId> mDiscoveryPriorityList;
private List<PrinterId> mTrackedPrinterList;
@@ -103,6 +107,7 @@
mSpooler = spooler;
mHandler = new MyHandler(context.getMainLooper());
mPrintServiceClient = new RemotePrintServiceClient(this);
+ mServiceDead = true;
}
public ComponentName getComponentName() {
@@ -144,10 +149,6 @@
mDestroyed = true;
}
- public void onAllPrintJobsHandled() {
- mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED);
- }
-
@Override
public void binderDied() {
mHandler.sendEmptyMessage(MyHandler.MSG_BINDER_DIED);
@@ -156,36 +157,35 @@
private void handleBinderDied() {
mPrintService.asBinder().unlinkToDeath(this, 0);
mPrintService = null;
+ mServiceDead = true;
mCallbacks.onServiceDied(this);
}
- public void dump(PrintWriter pw, String prefix) {
- String tab = " ";
- pw.append(prefix).append("service:").println();
- pw.append(prefix).append(tab).append("componentName=")
- .append(mComponentName.flattenToString()).println();
- pw.append(prefix).append(tab).append("destroyed=")
- .append(String.valueOf(mDestroyed)).println();
- pw.append(prefix).append(tab).append("bound=")
- .append(String.valueOf(isBound())).println();
- pw.append(prefix).append(tab).append("hasDicoverySession=")
- .append(String.valueOf(mHasPrinterDiscoverySession)).println();
- pw.append(prefix).append(tab).append("isDiscoveringPrinters=")
- .append(String.valueOf(mDiscoveryPriorityList != null)).println();
- pw.append(prefix).append(tab).append("trackedPrinters=")
- .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null");
+ public void onAllPrintJobsHandled() {
+ mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED);
}
private void handleOnAllPrintJobsHandled() {
throwIfDestroyed();
-
mHasActivePrintJobs = false;
-
- if (isBound()) {
+ if (!isBound()) {
+ // The service is dead and neither has active jobs nor discovery
+ // session, so ensure we are unbound since the service has no work.
+ if (mServiceDead && !mHasPrinterDiscoverySession) {
+ ensureUnbound();
+ return;
+ }
+ ensureBound();
+ mPendingCommands.add(new Runnable() {
+ @Override
+ public void run() {
+ handleOnAllPrintJobsHandled();
+ }
+ });
+ } else {
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] onAllPrintJobsHandled()");
}
-
// If the service has a printer discovery session
// created we should not disconnect from it just yet.
if (!mHasPrinterDiscoverySession) {
@@ -201,9 +201,15 @@
private void handleRequestCancelPrintJob(final PrintJobInfo printJob) {
throwIfDestroyed();
- // If we are not bound, then we have no print jobs to handle
- // which means that there are no print jobs to be cancelled.
- if (isBound()) {
+ if (!isBound()) {
+ ensureBound();
+ mPendingCommands.add(new Runnable() {
+ @Override
+ public void run() {
+ handleRequestCancelPrintJob(printJob);
+ }
+ });
+ } else {
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] requestCancelPrintJob()");
}
@@ -222,14 +228,12 @@
private void handleOnPrintJobQueued(final PrintJobInfo printJob) {
throwIfDestroyed();
-
mHasActivePrintJobs = true;
-
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@Override
- public void run() {
+ public void run() {
handleOnPrintJobQueued(printJob);
}
});
@@ -251,6 +255,7 @@
private void handleCreatePrinterDiscoverySession() {
throwIfDestroyed();
+ mHasPrinterDiscoverySession = true;
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -268,8 +273,6 @@
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error creating printer dicovery session.", re);
}
-
- mHasPrinterDiscoverySession = true;
}
}
@@ -279,7 +282,14 @@
private void handleDestroyPrinterDiscoverySession() {
throwIfDestroyed();
+ mHasPrinterDiscoverySession = false;
if (!isBound()) {
+ // The service is dead and neither has active jobs nor discovery
+ // session, so ensure we are unbound since the service has no work.
+ if (mServiceDead && !mHasActivePrintJobs) {
+ ensureUnbound();
+ return;
+ }
ensureBound();
mPendingCommands.add(new Runnable() {
@Override
@@ -291,15 +301,11 @@
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] destroyPrinterDiscoverySession()");
}
-
- mHasPrinterDiscoverySession = false;
-
try {
mPrintService.destroyPrinterDiscoverySession();
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error destroying printer dicovery session.", re);
}
-
// If the service has no print jobs and no active discovery
// session anymore we should disconnect from it.
if (!mHasActivePrintJobs) {
@@ -315,6 +321,11 @@
private void handleStartPrinterDiscovery(final List<PrinterId> priorityList) {
throwIfDestroyed();
+ // Take a note that we are doing discovery.
+ mDiscoveryPriorityList = new ArrayList<PrinterId>();
+ if (priorityList != null) {
+ mDiscoveryPriorityList.addAll(priorityList);
+ }
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -332,11 +343,6 @@
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error starting printer dicovery.", re);
}
- // Take a note that we are doing discovery.
- mDiscoveryPriorityList = new ArrayList<PrinterId>();
- if (priorityList != null) {
- mDiscoveryPriorityList.addAll(priorityList);
- }
}
}
@@ -346,6 +352,8 @@
private void handleStopPrinterDiscovery() {
throwIfDestroyed();
+ // We are not doing discovery anymore.
+ mDiscoveryPriorityList = null;
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -358,8 +366,6 @@
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()");
}
- // We are not doing discovery anymore.
- mDiscoveryPriorityList = null;
try {
mPrintService.stopPrinterDiscovery();
} catch (RemoteException re) {
@@ -402,6 +408,11 @@
private void handleStartPrinterStateTracking(final PrinterId printerId) {
throwIfDestroyed();
+ // Take a note we are tracking the printer.
+ if (mTrackedPrinterList == null) {
+ mTrackedPrinterList = new ArrayList<PrinterId>();
+ }
+ mTrackedPrinterList.add(printerId);
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -419,11 +430,6 @@
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error requesting start printer tracking.", re);
}
- // Take a note we are tracking the printer.
- if (mTrackedPrinterList == null) {
- mTrackedPrinterList = new ArrayList<PrinterId>();
- }
- mTrackedPrinterList.add(printerId);
}
}
@@ -434,6 +440,13 @@
private void handleStopPrinterStateTracking(final PrinterId printerId) {
throwIfDestroyed();
+ // We are no longer tracking the printer.
+ if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) {
+ return;
+ }
+ if (mTrackedPrinterList.isEmpty()) {
+ mTrackedPrinterList = null;
+ }
if (!isBound()) {
ensureBound();
mPendingCommands.add(new Runnable() {
@@ -446,13 +459,6 @@
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterTracking()");
}
- // We are no longer tracking the printer.
- if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) {
- return;
- }
- if (mTrackedPrinterList.isEmpty()) {
- mTrackedPrinterList = null;
- }
try {
mPrintService.stopPrinterStateTracking(printerId);
} catch (RemoteException re) {
@@ -461,6 +467,25 @@
}
}
+ public void dump(PrintWriter pw, String prefix) {
+ String tab = " ";
+ pw.append(prefix).append("service:").println();
+ pw.append(prefix).append(tab).append("componentName=")
+ .append(mComponentName.flattenToString()).println();
+ pw.append(prefix).append(tab).append("destroyed=")
+ .append(String.valueOf(mDestroyed)).println();
+ pw.append(prefix).append(tab).append("bound=")
+ .append(String.valueOf(isBound())).println();
+ pw.append(prefix).append(tab).append("hasDicoverySession=")
+ .append(String.valueOf(mHasPrinterDiscoverySession)).println();
+ pw.append(prefix).append(tab).append("hasActivePrintJobs=")
+ .append(String.valueOf(mHasActivePrintJobs)).println();
+ pw.append(prefix).append(tab).append("isDiscoveringPrinters=")
+ .append(String.valueOf(mDiscoveryPriorityList != null)).println();
+ pw.append(prefix).append(tab).append("trackedPrinters=")
+ .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null");
+ }
+
private boolean isBound() {
return mPrintService != null;
}
@@ -512,6 +537,7 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (mDestroyed || !mBinding) {
+ mContext.unbindService(mServiceConnection);
return;
}
mBinding = false;
@@ -529,31 +555,33 @@
handleBinderDied();
return;
}
- // If there is a session, then the service died after creating
- // a session. Hence, recreate the session.
- if (mHasPrinterDiscoverySession) {
+ // If the service died and there is a discovery session, recreate it.
+ if (mServiceDead && mHasPrinterDiscoverySession) {
handleCreatePrinterDiscoverySession();
}
- // If there is a priority list, then the service died during
- // discovery and is restarted. Hence, start discovery.
- if (mDiscoveryPriorityList != null) {
+ // If the service died and there is discovery started, restart it.
+ if (mServiceDead && mDiscoveryPriorityList != null) {
handleStartPrinterDiscovery(mDiscoveryPriorityList);
}
- // If there is a tracked printer list, then the service died
- // during discovery and is restarted. Hence, start tracking.
- if (mTrackedPrinterList != null) {
+ // If the service died and printers were tracked, start tracking.
+ if (mServiceDead && mTrackedPrinterList != null) {
final int trackedPrinterCount = mTrackedPrinterList.size();
for (int i = 0; i < trackedPrinterCount; i++) {
handleStartPrinterStateTracking(mTrackedPrinterList.get(i));
}
}
// Finally, do all the pending work.
- final int pendingCommandCount = mPendingCommands.size();
- for (int i = 0; i < pendingCommandCount; i++) {
- Runnable pendingCommand = mPendingCommands.get(i);
+ while (!mPendingCommands.isEmpty()) {
+ Runnable pendingCommand = mPendingCommands.remove(0);
pendingCommand.run();
}
- mPendingCommands.clear();
+ // We did a best effort to get to the last state if we crashed.
+ // If we do not have print jobs and no discovery is in progress,
+ // then no need to be bound.
+ if (!mHasPrinterDiscoverySession && !mHasActivePrintJobs) {
+ ensureUnbound();
+ }
+ mServiceDead = false;
}
@Override
@@ -664,7 +692,7 @@
}
@Override
- public PrintJobInfo getPrintJobInfo(int printJobId) {
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -679,7 +707,7 @@
}
@Override
- public boolean setPrintJobState(int printJobId, int state, String error) {
+ public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -693,7 +721,7 @@
}
@Override
- public boolean setPrintJobTag(int printJobId, String tag) {
+ public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -707,7 +735,7 @@
}
@Override
- public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
RemotePrintService service = mWeakService.get();
if (service != null) {
final long identity = Binder.clearCallingIdentity();
@@ -720,13 +748,15 @@
}
@Override
- public void onPrintersAdded(List<PrinterInfo> printers) {
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void onPrintersAdded(ParceledListSlice printers) {
RemotePrintService service = mWeakService.get();
if (service != null) {
- throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers);
+ List<PrinterInfo> addedPrinters = (List<PrinterInfo>) printers.getList();
+ throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, addedPrinters);
final long identity = Binder.clearCallingIdentity();
try {
- service.mCallbacks.onPrintersAdded(printers);
+ service.mCallbacks.onPrintersAdded(addedPrinters);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -734,13 +764,15 @@
}
@Override
- public void onPrintersRemoved(List<PrinterId> printerIds) {
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void onPrintersRemoved(ParceledListSlice printerIds) {
RemotePrintService service = mWeakService.get();
if (service != null) {
- throwIfPrinterIdsTampered(service.mComponentName, printerIds);
+ List<PrinterId> removedPrinterIds = (List<PrinterId>) printerIds.getList();
+ throwIfPrinterIdsTampered(service.mComponentName, removedPrinterIds);
final long identity = Binder.clearCallingIdentity();
try {
- service.mCallbacks.onPrintersRemoved(printerIds);
+ service.mCallbacks.onPrintersRemoved(removedPrinterIds);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
index 45469ac..1bde6d7 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -31,20 +31,20 @@
import android.print.IPrintSpooler;
import android.print.IPrintSpoolerCallbacks;
import android.print.IPrintSpoolerClient;
-import android.print.PrintAttributes;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
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
* PrintManagerSerivce. It is responsible to connecting to the remote
@@ -64,8 +64,6 @@
private final GetPrintJobInfosCaller mGetPrintJobInfosCaller = new GetPrintJobInfosCaller();
- private final CreatePrintJobCaller mCreatePrintJobCaller = new CreatePrintJobCaller();
-
private final GetPrintJobInfoCaller mGetPrintJobInfoCaller = new GetPrintJobInfoCaller();
private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller();
@@ -132,16 +130,15 @@
return null;
}
- public final PrintJobInfo createPrintJob(String printJobName, IPrintClient client,
- IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId) {
+ public final void createPrintJob(PrintJobInfo printJob, IPrintClient client,
+ IPrintDocumentAdapter documentAdapter) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
- return mCreatePrintJobCaller.createPrintJob(getRemoteInstanceLazy(),
- printJobName, client, documentAdapter, attributes, appId);
+ getRemoteInstanceLazy().createPrintJob(printJob, client, documentAdapter);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error creating print job.", re);
} catch (TimeoutException te) {
@@ -155,10 +152,9 @@
mLock.notifyAll();
}
}
- return null;
}
- public final void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public final void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -184,7 +180,7 @@
}
}
- public final PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
+ public final PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -209,7 +205,7 @@
return null;
}
- public final boolean setPrintJobState(int printJobId, int state, String error) {
+ public final boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -234,7 +230,7 @@
return false;
}
- public final boolean setPrintJobTag(int printJobId, String tag) {
+ public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -259,19 +255,46 @@
return false;
}
- public final void start() {
+ public final void removeObsoletePrintJobs() {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
- getRemoteInstanceLazy();
+ getRemoteInstanceLazy().removeObsoletePrintJobs();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error removing obsolete print jobs .", re);
} catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error starting the spooler.", te);
+ Slog.e(LOG_TAG, "Error removing obsolete print jobs .", te);
} finally {
if (DEBUG) {
- Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] start()");
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ + "] removeObsoletePrintJobs()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
+ public final void forgetPrintJobs(List<PrintJobId> printJobIds) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ getRemoteInstanceLazy().forgetPrintJobs(printJobIds);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error forgeting print jobs", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error forgeting print jobs", te);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ + "] forgetPrintJobs()");
}
synchronized (mLock) {
mCanUnbind = true;
@@ -333,6 +356,9 @@
}
private void bindLocked() throws TimeoutException {
+ if (mRemoteInstance != null) {
+ return;
+ }
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked()");
}
@@ -362,6 +388,9 @@
}
private void unbindLocked() {
+ if (mRemoteInstance == null) {
+ return;
+ }
while (true) {
if (mCanUnbind) {
if (DEBUG) {
@@ -452,29 +481,6 @@
}
}
- private static final class CreatePrintJobCaller extends TimedRemoteCaller<PrintJobInfo> {
- private final IPrintSpoolerCallbacks mCallback;
-
- public CreatePrintJobCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
- mCallback = new BasePrintSpoolerServiceCallbacks() {
- @Override
- public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
- onRemoteMethodResult(printJob, sequence);
- }
- };
- }
-
- public PrintJobInfo createPrintJob(IPrintSpooler target, String printJobName,
- IPrintClient client, IPrintDocumentAdapter documentAdapter,
- PrintAttributes attributes, int appId) throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- target.createPrintJob(printJobName, client, documentAdapter, attributes,
- mCallback, appId, sequence);
- return getResultTimed(sequence);
- }
- }
-
private static final class GetPrintJobInfoCaller extends TimedRemoteCaller<PrintJobInfo> {
private final IPrintSpoolerCallbacks mCallback;
@@ -488,7 +494,7 @@
};
}
- public PrintJobInfo getPrintJobInfo(IPrintSpooler target, int printJobId,
+ public PrintJobInfo getPrintJobInfo(IPrintSpooler target, PrintJobId printJobId,
int appId) throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.getPrintJobInfo(printJobId, mCallback, appId, sequence);
@@ -509,7 +515,7 @@
};
}
- public boolean setPrintJobState(IPrintSpooler target, int printJobId,
+ public boolean setPrintJobState(IPrintSpooler target, PrintJobId printJobId,
int status, String error) throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.setPrintJobState(printJobId, status, error, mCallback, sequence);
@@ -530,7 +536,7 @@
};
}
- public boolean setPrintJobTag(IPrintSpooler target, int printJobId,
+ public boolean setPrintJobTag(IPrintSpooler target, PrintJobId printJobId,
String tag) throws RemoteException, TimeoutException {
final int sequence = onBeforeRemoteCall();
target.setPrintJobTag(printJobId, tag, mCallback, sequence);
@@ -551,11 +557,6 @@
}
@Override
- public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
- /* do nothing */
- }
-
- @Override
public void onCancelPrintJobResult(boolean canceled, int sequence) {
/* do nothing */
}
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
index 86a5aed..fd4a3a4 100644
--- a/services/java/com/android/server/print/UserState.java
+++ b/services/java/com/android/server/print/UserState.java
@@ -21,17 +21,24 @@
import android.content.Intent;
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.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.UserManager;
+import android.print.IPrintClient;
+import android.print.IPrintDocumentAdapter;
import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintAttributes;
+import android.print.PrintJobId;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterId;
@@ -46,6 +53,7 @@
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.os.SomeArgs;
import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
@@ -56,7 +64,6 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
@@ -68,8 +75,6 @@
private static final boolean DEBUG = false;
- private static final int MAX_ITEMS_PER_CALLBACK = 50;
-
private static final char COMPONENT_NAME_SEPARATOR = ':';
private final SimpleStringSplitter mStringColonSplitter =
@@ -87,6 +92,9 @@
private final Set<ComponentName> mEnabledServices =
new ArraySet<ComponentName>();
+ private final CreatedPrintJobTracker mCreatedPrintJobTracker =
+ new CreatedPrintJobTracker();
+
private final Object mLock;
private final Context mContext;
@@ -134,6 +142,99 @@
}
}
+ public void removeObsoletePrintJobs() {
+ mSpooler.removeObsoletePrintJobs();
+ }
+
+ public PrintJobInfo print(String printJobName, final IPrintClient client,
+ final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
+ int appId) {
+ PrintJobId printJobId = new PrintJobId();
+
+ // Track this job so we can forget it when the creator dies.
+ if (!mCreatedPrintJobTracker.onPrintJobCreatedLocked(client.asBinder(), printJobId)) {
+ // Not adding a print job means the client is dead - done.
+ return null;
+ }
+
+ // Create print job place holder.
+ final PrintJobInfo printJob = new PrintJobInfo();
+ printJob.setId(printJobId);
+ printJob.setAppId(appId);
+ printJob.setLabel(printJobName);
+ printJob.setAttributes(attributes);
+ printJob.setState(PrintJobInfo.STATE_CREATED);
+
+ // Spin the spooler to add the job and show the config UI.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ mSpooler.createPrintJob(printJob, client, documentAdapter);
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+
+ return printJob;
+ }
+
+ public List<PrintJobInfo> getPrintJobInfos(int appId) {
+ return mSpooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY, appId);
+ }
+
+ public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+ return mSpooler.getPrintJobInfo(printJobId, appId);
+ }
+
+ public void cancelPrintJob(PrintJobId printJobId, int appId) {
+ PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
+ if (printJobInfo == null) {
+ return;
+ }
+ if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
+ ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
+ RemotePrintService printService = null;
+ synchronized (mLock) {
+ printService = mActiveServices.get(printServiceName);
+ }
+ if (printService == null) {
+ return;
+ }
+ printService.onRequestCancelPrintJob(printJobInfo);
+ } else {
+ // If the print job is failed we do not need cooperation
+ // from the print service.
+ mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null);
+ }
+ }
+
+ public void restartPrintJob(PrintJobId printJobId, int appId) {
+ PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId);
+ if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
+ return;
+ }
+ mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
+ }
+
+ public List<PrintServiceInfo> getEnabledPrintServices() {
+ synchronized (mLock) {
+ List<PrintServiceInfo> enabledServices = null;
+ final int installedServiceCount = mInstalledServices.size();
+ for (int i = 0; i < installedServiceCount; i++) {
+ PrintServiceInfo installedService = mInstalledServices.get(i);
+ ComponentName componentName = new ComponentName(
+ installedService.getResolveInfo().serviceInfo.packageName,
+ installedService.getResolveInfo().serviceInfo.name);
+ if (mActiveServices.containsKey(componentName)) {
+ if (enabledServices == null) {
+ enabledServices = new ArrayList<PrintServiceInfo>();
+ }
+ enabledServices.add(installedService);
+ }
+ }
+ return enabledServices;
+ }
+ }
+
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -292,6 +393,7 @@
}
// Fail all print jobs.
failActivePrintJobsForService(service.getComponentName());
+ service.onAllPrintJobsHandled();
// No session - nothing to do.
if (mPrinterDiscoverySession == null) {
return;
@@ -307,18 +409,6 @@
}
}
- public RemotePrintSpooler getSpoolerLocked() {
- throwIfDestroyedLocked();
- return mSpooler;
- }
-
- public Map<ComponentName, RemotePrintService> getActiveServicesLocked() {
- synchronized(mLock) {
- throwIfDestroyedLocked();
- return mActiveServices;
- }
- }
-
public Set<ComponentName> getEnabledServices() {
synchronized(mLock) {
throwIfDestroyedLocked();
@@ -572,13 +662,12 @@
// just died. Do this off the main thread since we do to allow
// calls into the spooler on the main thread.
if (Looper.getMainLooper().isCurrentThread()) {
- new AsyncTask<Void, Void, Void>() {
+ BackgroundThread.getHandler().post(new Runnable() {
@Override
- protected Void doInBackground(Void... params) {
+ public void run() {
failActivePrintJobsForServiceInternal(serviceName);
- return null;
}
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ });
} else {
failActivePrintJobsForServiceInternal(serviceName);
}
@@ -984,11 +1073,11 @@
removedPrinterIds.add(printerId);
}
}
- final int removedPrinterCount = removedPrinterIds.size();
- for (int i = 0; i < removedPrinterCount; i++) {
- mPrinters.remove(removedPrinterIds.get(i));
- }
if (removedPrinterIds != null) {
+ final int removedPrinterCount = removedPrinterIds.size();
+ for (int i = 0; i < removedPrinterCount; i++) {
+ mPrinters.remove(removedPrinterIds.get(i));
+ }
mHandler.obtainMessage(
SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
removedPrinterIds).sendToTarget();
@@ -1067,19 +1156,7 @@
private void handlePrintersAdded(IPrinterDiscoveryObserver observer,
List<PrinterInfo> printers) {
try {
- final int printerCount = printers.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersAdded(printers);
- } else {
- // Send the added printers in chunks avoiding the binder transaction limit.
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterInfo> subPrinters = printers.subList(start, end);
- observer.onPrintersAdded(subPrinters);
- }
- }
+ observer.onPrintersAdded(new ParceledListSlice<PrinterInfo>(printers));
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error sending added printers", re);
}
@@ -1088,21 +1165,9 @@
private void handlePrintersRemoved(IPrinterDiscoveryObserver observer,
List<PrinterId> printerIds) {
try {
- final int printerCount = printerIds.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersRemoved(printerIds);
- } else {
- // Send the added printers in chunks avoiding the binder transaction limit.
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterId> subPrinterIds = printerIds.subList(start, end);
- observer.onPrintersRemoved(subPrinterIds);
- }
- }
+ observer.onPrintersRemoved(new ParceledListSlice<PrinterId>(printerIds));
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending added printers", re);
+ Log.e(LOG_TAG, "Error sending removed printers", re);
}
}
@@ -1234,4 +1299,51 @@
}
}
}
-}
\ No newline at end of file
+
+ private final class CreatedPrintJobTracker {
+ private final ArrayMap<IBinder, List<PrintJobId>> mCreatedPrintJobs =
+ new ArrayMap<IBinder, List<PrintJobId>>();
+
+ public boolean onPrintJobCreatedLocked(final IBinder creator, PrintJobId printJobId) {
+ try {
+ creator.linkToDeath(new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ creator.unlinkToDeath(this, 0);
+ UserManager userManager = (UserManager) mContext.getSystemService(
+ Context.USER_SERVICE);
+ // If the death is a result of the user being removed, then
+ // do nothing since the spooler data for this user will be
+ // wiped and we cannot bind to the spooler at this point.
+ if (userManager.getUserInfo(mUserId) == null) {
+ return;
+ }
+ List<PrintJobId> printJobIds = null;
+ synchronized (mLock) {
+ printJobIds = mCreatedPrintJobs.remove(creator);
+ if (printJobIds == null) {
+ return;
+ }
+ printJobIds = new ArrayList<PrintJobId>(printJobIds);
+ }
+ if (printJobIds != null) {
+ mSpooler.forgetPrintJobs(printJobIds);
+ }
+ }
+ }, 0);
+ } catch (RemoteException re) {
+ /* The process is already dead - we just failed. */
+ return false;
+ }
+ synchronized (mLock) {
+ List<PrintJobId> printJobIds = mCreatedPrintJobs.get(creator);
+ if (printJobIds == null) {
+ printJobIds = new ArrayList<PrintJobId>();
+ mCreatedPrintJobs.put(creator, printJobIds);
+ }
+ printJobIds.add(printJobId);
+ }
+ return true;
+ }
+ }
+}
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index 5a24ebb..bbcd01a 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -172,10 +172,16 @@
case WifiManager.CONNECT_NETWORK:
case WifiManager.SAVE_NETWORK: {
WifiConfiguration config = (WifiConfiguration) msg.obj;
- if (config.isValid()) {
+ int networkId = msg.arg1;
+ if (config != null && config.isValid()) {
+ if (DBG) Slog.d(TAG, "Connect with config" + config);
+ mWifiStateMachine.sendMessage(Message.obtain(msg));
+ } else if (config == null
+ && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
+ if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
mWifiStateMachine.sendMessage(Message.obtain(msg));
} else {
- Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
+ Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
if (msg.what == WifiManager.CONNECT_NETWORK) {
replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED);
} else {
@@ -582,7 +588,8 @@
*/
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
enforceChangePermission();
- if (wifiConfig.isValid()) {
+ // null wifiConfig is a meaningful input for CMD_SET_AP
+ if (wifiConfig == null || wifiConfig.isValid()) {
mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
} else {
Slog.e(TAG, "Invalid WifiConfiguration");
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index ea3af26..2e13fe2 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -345,7 +345,7 @@
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
mService.mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
}
-
+
/* Provides an opportunity for the window manager policy to intercept early key
* processing as soon as the key has been read from the device. */
@Override
@@ -370,7 +370,7 @@
WindowState windowState = focus != null ? (WindowState) focus.windowState : null;
return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
}
-
+
/* Provides an opportunity for the window manager policy to process a key that
* the application did not handle. */
@Override
@@ -392,7 +392,7 @@
* Layer assignment is assumed to be complete by the time this is called.
*/
public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
- if (WindowManagerService.DEBUG_INPUT) {
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT || WindowManagerService.DEBUG_INPUT) {
Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow);
}
@@ -412,7 +412,7 @@
}
}
}
-
+
public void setFocusedAppLw(AppWindowToken newApp) {
// Focused app has changed.
if (newApp == null) {
@@ -425,7 +425,7 @@
mService.mInputManager.setFocusedApplication(handle);
}
}
-
+
public void pauseDispatchingLw(WindowToken window) {
if (! window.paused) {
if (WindowManagerService.DEBUG_INPUT) {
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 25b042c..ca87b4f 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -293,6 +293,8 @@
// We are showing on to of the current
// focus, so re-evaluate focus to make
// sure it is correct.
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.v(TAG,
+ "updateWindowsLocked: setting mFocusMayChange true");
mService.mFocusMayChange = true;
}
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index f5e0531..d9e49b3 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -160,6 +160,7 @@
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
static final boolean DEBUG_FOCUS = false;
+ static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || true;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_RESIZE = false;
@@ -921,8 +922,9 @@
//apptoken note that the window could be a floating window
//that was created later or a window at the top of the list of
//windows associated with this token.
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
- "Adding window " + win + " at " + (newIdx + 1) + " of " + N);
+ if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " +
+ N);
windows.add(newIdx + 1, win);
if (newIdx < 0) {
// No window from token found on win's display.
@@ -1042,8 +1044,8 @@
break;
}
}
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
- "Adding window " + win + " at " + i + " of " + N);
+ if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "Based on layer: Adding window " + win + " at " + i + " of " + N);
windows.add(i, win);
mWindowsChanged = true;
return tokenWindowsPos;
@@ -1061,8 +1063,8 @@
}
}
i++;
- if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
- "Adding window " + win + " at " + i + " of " + windows.size());
+ if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "Free window: Adding window " + win + " at " + i + " of " + windows.size());
windows.add(i, win);
mWindowsChanged = true;
}
@@ -1129,6 +1131,8 @@
}
private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
+ if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win +
+ " Callers=" + Debug.getCallers(4));
if (win.mAttachedWindow == null) {
final WindowToken token = win.mToken;
int tokenWindowsPos = 0;
@@ -2353,7 +2357,7 @@
public void removeWindowLocked(Session session, WindowState win) {
- if (localLOGV || DEBUG_FOCUS) Slog.v(
+ if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win==mCurrentFocus) Slog.v(
TAG, "Remove " + win + " client="
+ Integer.toHexString(System.identityHashCode(win.mClient.asBinder()))
+ ", surface=" + win.mWinAnimator.mSurfaceControl,
@@ -3771,7 +3775,7 @@
synchronized(mWindowMap) {
boolean changed = false;
if (token == null) {
- if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
changed = mFocusedApp != null;
mFocusedApp = null;
if (changed) {
@@ -3784,9 +3788,9 @@
return;
}
changed = mFocusedApp != newFocus;
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Set focused app to: " + newFocus
+ + " old focus=" + mFocusedApp + " moveFocusNow=" + moveFocusNow);
mFocusedApp = newFocus;
- if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp
- + " moveFocusNow=" + moveFocusNow);
if (changed) {
mInputMonitor.setFocusedAppLw(newFocus);
}
@@ -4508,7 +4512,7 @@
}
unsetAppFreezingScreenLocked(wtoken, true, true);
if (mFocusedApp == wtoken) {
- if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken);
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Removing focused app token:" + wtoken);
mFocusedApp = null;
updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
mInputMonitor.setFocusedAppLw(null);
@@ -7070,8 +7074,8 @@
return;
}
mLastFocus = newFocus;
- //Slog.i(TAG, "Focus moving from " + lastFocus
- // + " to " + newFocus);
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Focus moving from " + lastFocus +
+ " to " + newFocus);
if (newFocus != null && lastFocus != null
&& !newFocus.isDisplayedLw()) {
//Slog.i(TAG, "Delaying loss of focus...");
@@ -7080,19 +7084,17 @@
}
}
- if (lastFocus != newFocus) {
- //System.out.println("Changing focus from " + lastFocus
- // + " to " + newFocus);
- if (newFocus != null) {
- //Slog.i(TAG, "Gaining focus: " + newFocus);
- newFocus.reportFocusChangedSerialized(true, mInTouchMode);
- notifyFocusChanged();
- }
+ //System.out.println("Changing focus from " + lastFocus
+ // + " to " + newFocus);
+ if (newFocus != null) {
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Gaining focus: " + newFocus);
+ newFocus.reportFocusChangedSerialized(true, mInTouchMode);
+ notifyFocusChanged();
+ }
- if (lastFocus != null) {
- //Slog.i(TAG, "Losing focus: " + lastFocus);
- lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
- }
+ if (lastFocus != null) {
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing focus: " + lastFocus);
+ lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
}
} break;
@@ -7106,7 +7108,8 @@
final int N = losers.size();
for (int i=0; i<N; i++) {
- //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
+ if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing delayed focus: " +
+ losers.get(i));
losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
}
} break;
@@ -9709,7 +9712,7 @@
newFocus = computeFocusedWindowLocked();
}
- if (localLOGV) Slog.v(
+ if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(
TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
@@ -9816,10 +9819,9 @@
tokens = tasks.get(taskNdx).mAppTokens;
for ( ; tokenNdx >= 0; --tokenNdx) {
if (nextApp == mFocusedApp) {
- // Whoops, we are below the focused app... no focus
- // for you!
+ // Whoops, we are below the focused app... no focus for you!
if (localLOGV || DEBUG_FOCUS) Slog.v(
- TAG, "Reached focused app: " + mFocusedApp);
+ TAG, "findFocusedWindow: Reached focused app=" + mFocusedApp);
return null;
}
nextApp = tokens.get(tokenNdx);
@@ -9844,11 +9846,12 @@
// Dispatch to this window if it is wants key events.
if (win.canReceiveKeys()) {
- if (DEBUG_FOCUS) Slog.v(
- TAG, "Found focus @ " + i + " = " + win);
+ if (DEBUG_FOCUS_LIGHT) Slog.v(
+ TAG, "findFocusedWindow: Found new focus @ " + i + " = " + win);
return win;
}
}
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: No focusable windows.");
return null;
}
@@ -10275,14 +10278,13 @@
void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
- int j = 0;
final int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
final WindowState w = windowList.get(winNdx);
if (windows == null || windows.contains(w)) {
- pw.print(" Window #"); pw.print(j++); pw.print(' ');
+ pw.print(" Window #"); pw.print(winNdx); pw.print(' ');
pw.print(w); pw.println(":");
w.dump(pw, " ", dumpAll || windows != null);
}
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 21445d3..64b5a09 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -1142,6 +1142,8 @@
// we allow the display to be enabled now.
mService.enableScreenIfNeededLocked();
if (mService.mCurrentFocus == this) {
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
+ "WindowState.hideLw: setting mFocusMayChange true");
mService.mFocusMayChange = true;
}
}
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 9245542..533f626 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -340,6 +340,8 @@
mWin.mDisplayContent.layoutNeeded = true;
if (!mWin.mPolicyVisibility) {
if (mService.mCurrentFocus == mWin) {
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
+ "setAnimationLocked: setting mFocusMayChange true");
mService.mFocusMayChange = true;
}
// Window is no longer visible -- make sure if we were waiting
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 2ce584b..2b3c9e2 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -355,7 +355,15 @@
*/
public boolean isValid() {
if (allowedKeyManagement.cardinality() > 1) {
- return false;
+ if (allowedKeyManagement.cardinality() != 2) {
+ return false;
+ }
+ if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) == false) {
+ return false;
+ }
+ if (allowedKeyManagement.get(KeyMgmt.IEEE8021X) == false) {
+ return false;
+ }
}
// TODO: Add more checks