Merge "Revert "Take the input device into account for meta state"" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 0d65629..739ef4c 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";
@@ -7258,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";
@@ -10862,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
@@ -10987,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;
@@ -11131,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;
@@ -11146,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 {
@@ -12334,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();
@@ -12343,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 {
@@ -12423,7 +12431,7 @@
     method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
     method public final void release();
     method public final void releaseOutputBuffer(int, boolean);
-    method public final void setParameters(java.util.Map<java.lang.String, java.lang.Object>);
+    method public final void setParameters(android.os.Bundle);
     method public final void setVideoScalingMode(int);
     method public final void signalEndOfInputStream();
     method public final void start();
@@ -12439,7 +12447,7 @@
     field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
     field public static final java.lang.String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
     field public static final java.lang.String PARAMETER_KEY_SUSPEND = "drop-input-frames";
-    field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "videoBitrate";
+    field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -12750,6 +12758,9 @@
     field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
     field public static final java.lang.String KEY_HEIGHT = "height";
     field public static final java.lang.String KEY_IS_ADTS = "is-adts";
+    field public static final java.lang.String KEY_IS_AUTOSELECT = "is-autoselect";
+    field public static final java.lang.String KEY_IS_DEFAULT = "is-default";
+    field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
     field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
     field public static final java.lang.String KEY_LANGUAGE = "language";
     field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
@@ -12762,6 +12773,25 @@
     field public static final java.lang.String KEY_WIDTH = "width";
   }
 
+  public abstract class MediaMetadataEditor {
+    method public synchronized void addEditableKey(int);
+    method public abstract void apply();
+    method public synchronized void clear();
+    method public synchronized android.graphics.Bitmap getBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method public synchronized int[] getEditableKeys();
+    method public synchronized long getLong(int, long) throws java.lang.IllegalArgumentException;
+    method public synchronized java.lang.Object getObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+    method public synchronized java.lang.String getString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+    method public synchronized void removeEditableKeys();
+    field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
+    field public static final int RATING_KEY_BY_OTHERS = 101; // 0x65
+    field public static final int RATING_KEY_BY_USER = 268435457; // 0x10000001
+  }
+
   public class MediaMetadataRetriever {
     ctor public MediaMetadataRetriever();
     method public java.lang.String extractMetadata(int);
@@ -13178,6 +13208,29 @@
     ctor public NotProvisionedException(java.lang.String);
   }
 
+  public final class Rating implements android.os.Parcelable {
+    method public int describeContents();
+    method public float getPercentRating();
+    method public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static android.media.Rating newHeartRating(boolean);
+    method public static android.media.Rating newPercentageRating(float);
+    method public static android.media.Rating newStarRating(int, float);
+    method public static android.media.Rating newThumbRating(boolean);
+    method public static android.media.Rating newUnratedRating(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
   public class RemoteControlClient {
     ctor public RemoteControlClient(android.app.PendingIntent);
     ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
@@ -13209,21 +13262,9 @@
     field public static final int PLAYSTATE_STOPPED = 1; // 0x1
   }
 
-  public class RemoteControlClient.MetadataEditor {
-    method public synchronized void addEditableKey(int);
+  public class RemoteControlClient.MetadataEditor extends android.media.MediaMetadataEditor {
     method public synchronized void apply();
-    method public synchronized void clear();
-    method public synchronized void clearEditableKeys();
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
     field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
-    field public static final int LONG_KEY_RATING_BY_OTHERS = 102; // 0x66
-    field public static final int LONG_KEY_RATING_BY_USER = 268435457; // 0x10000001
-    field public static final int LONG_KEY_RATING_TYPE = 101; // 0x65
-    field public static final long RATING_HEART = -1L; // 0xffffffffffffffffL
-    field public static final long RATING_NOT_RATED = -101L; // 0xffffffffffffff9bL
-    field public static final long RATING_THUMB_UP_DOWN = -2L; // 0xfffffffffffffffeL
   }
 
   public static abstract interface RemoteControlClient.OnGetPlaybackPositionListener {
@@ -13231,9 +13272,7 @@
   }
 
   public static abstract interface RemoteControlClient.OnMetadataUpdateListener {
-    method public abstract void onMetadataUpdateBitmap(int, android.graphics.Bitmap);
-    method public abstract void onMetadataUpdateLong(int, long);
-    method public abstract void onMetadataUpdateString(int, java.lang.String);
+    method public abstract void onMetadataUpdate(int, java.lang.Object);
   }
 
   public static abstract interface RemoteControlClient.OnPlaybackPositionUpdateListener {
@@ -13634,6 +13673,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();
@@ -19102,12 +19147,54 @@
     field public static final android.print.PrintAttributes.MediaSize ISO_C7;
     field public static final android.print.PrintAttributes.MediaSize ISO_C8;
     field public static final android.print.PrintAttributes.MediaSize ISO_C9;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B0;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B1;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B10;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B2;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B3;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B4;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B5;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B6;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B7;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B8;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B9;
+    field public static final android.print.PrintAttributes.MediaSize JIS_EXEC;
+    field public static final android.print.PrintAttributes.MediaSize JPN_CHOU2;
+    field public static final android.print.PrintAttributes.MediaSize JPN_CHOU3;
+    field public static final android.print.PrintAttributes.MediaSize JPN_CHOU4;
+    field public static final android.print.PrintAttributes.MediaSize JPN_HAGAKI;
+    field public static final android.print.PrintAttributes.MediaSize JPN_KAHU;
+    field public static final android.print.PrintAttributes.MediaSize JPN_KAKU2;
+    field public static final android.print.PrintAttributes.MediaSize JPN_OUFUKU;
+    field public static final android.print.PrintAttributes.MediaSize JPN_YOU4;
+    field public static final android.print.PrintAttributes.MediaSize NA_FOOLSCAP;
     field public static final android.print.PrintAttributes.MediaSize NA_GOVT_LETTER;
+    field public static final android.print.PrintAttributes.MediaSize NA_INDEX_3X5;
+    field public static final android.print.PrintAttributes.MediaSize NA_INDEX_4X6;
+    field public static final android.print.PrintAttributes.MediaSize NA_INDEX_5X8;
     field public static final android.print.PrintAttributes.MediaSize NA_JUNIOR_LEGAL;
     field public static final android.print.PrintAttributes.MediaSize NA_LEDGER;
     field public static final android.print.PrintAttributes.MediaSize NA_LEGAL;
     field public static final android.print.PrintAttributes.MediaSize NA_LETTER;
+    field public static final android.print.PrintAttributes.MediaSize NA_MONARCH;
+    field public static final android.print.PrintAttributes.MediaSize NA_QUARTO;
     field public static final android.print.PrintAttributes.MediaSize NA_TBLOID;
+    field public static final android.print.PrintAttributes.MediaSize OM_DAI_PA_KAI;
+    field public static final android.print.PrintAttributes.MediaSize OM_JUURO_KU_KAI;
+    field public static final android.print.PrintAttributes.MediaSize OM_PA_KAI;
+    field public static final android.print.PrintAttributes.MediaSize PRC_1;
+    field public static final android.print.PrintAttributes.MediaSize PRC_10;
+    field public static final android.print.PrintAttributes.MediaSize PRC_16k;
+    field public static final android.print.PrintAttributes.MediaSize PRC_2;
+    field public static final android.print.PrintAttributes.MediaSize PRC_3;
+    field public static final android.print.PrintAttributes.MediaSize PRC_4;
+    field public static final android.print.PrintAttributes.MediaSize PRC_5;
+    field public static final android.print.PrintAttributes.MediaSize PRC_6;
+    field public static final android.print.PrintAttributes.MediaSize PRC_7;
+    field public static final android.print.PrintAttributes.MediaSize PRC_8;
+    field public static final android.print.PrintAttributes.MediaSize PRC_9;
+    field public static final android.print.PrintAttributes.MediaSize ROC_16K;
+    field public static final android.print.PrintAttributes.MediaSize ROC_8K;
   }
 
   public static final class PrintAttributes.Resolution {
@@ -19168,15 +19255,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();
@@ -19188,6 +19281,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
@@ -19195,7 +19289,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);
   }
 
@@ -19306,7 +19399,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();
@@ -27244,6 +27337,7 @@
     method public float getScaleFactor();
     method public long getTimeDelta();
     method public boolean isInProgress();
+    method public boolean isQuickScaleEnabled();
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public void setQuickScaleEnabled(boolean);
   }
@@ -29914,7 +30008,7 @@
     method public deprecated void onConsoleMessage(java.lang.String, int, java.lang.String);
     method public boolean onConsoleMessage(android.webkit.ConsoleMessage);
     method public boolean onCreateWindow(android.webkit.WebView, boolean, boolean, android.os.Message);
-    method public void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onGeolocationPermissionsHidePrompt();
     method public void onGeolocationPermissionsShowPrompt(java.lang.String, android.webkit.GeolocationPermissions.Callback);
     method public void onHideCustomView();
@@ -29924,7 +30018,7 @@
     method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
     method public deprecated boolean onJsTimeout();
     method public void onProgressChanged(android.webkit.WebView, int);
-    method public void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
     method public void onReceivedTitle(android.webkit.WebView, java.lang.String);
     method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
@@ -29980,12 +30074,12 @@
     method public int getCacheMode();
     method public synchronized java.lang.String getCursiveFontFamily();
     method public synchronized boolean getDatabaseEnabled();
-    method public synchronized java.lang.String getDatabasePath();
+    method public deprecated synchronized java.lang.String getDatabasePath();
     method public synchronized int getDefaultFixedFontSize();
     method public synchronized int getDefaultFontSize();
     method public synchronized java.lang.String getDefaultTextEncodingName();
     method public static java.lang.String getDefaultUserAgent(android.content.Context);
-    method public android.webkit.WebSettings.ZoomDensity getDefaultZoom();
+    method public deprecated android.webkit.WebSettings.ZoomDensity getDefaultZoom();
     method public boolean getDisplayZoomControls();
     method public synchronized boolean getDomStorageEnabled();
     method public synchronized java.lang.String getFantasyFontFamily();
@@ -30022,11 +30116,11 @@
     method public void setCacheMode(int);
     method public synchronized void setCursiveFontFamily(java.lang.String);
     method public synchronized void setDatabaseEnabled(boolean);
-    method public synchronized void setDatabasePath(java.lang.String);
+    method public deprecated synchronized void setDatabasePath(java.lang.String);
     method public synchronized void setDefaultFixedFontSize(int);
     method public synchronized void setDefaultFontSize(int);
     method public synchronized void setDefaultTextEncodingName(java.lang.String);
-    method public void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
+    method public deprecated void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
     method public void setDisplayZoomControls(boolean);
     method public synchronized void setDomStorageEnabled(boolean);
     method public deprecated void setEnableSmoothTransition(boolean);
@@ -30069,9 +30163,10 @@
   public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
     method public static android.webkit.WebSettings.LayoutAlgorithm valueOf(java.lang.String);
     method public static final android.webkit.WebSettings.LayoutAlgorithm[] values();
-    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
+    enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
     enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NORMAL;
     enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
+    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm TEXT_AUTOSIZING;
   }
 
   public static final class WebSettings.PluginState extends java.lang.Enum {
@@ -30124,7 +30219,7 @@
     method public long getUsage();
   }
 
-  public static abstract interface WebStorage.QuotaUpdater {
+  public static abstract deprecated interface WebStorage.QuotaUpdater {
     method public abstract void updateQuota(long);
   }
 
@@ -30152,7 +30247,7 @@
     method public boolean canGoForward();
     method public deprecated boolean canZoomIn();
     method public deprecated boolean canZoomOut();
-    method public android.graphics.Picture capturePicture();
+    method public deprecated android.graphics.Picture capturePicture();
     method public void clearCache(boolean);
     method public void clearFormData();
     method public void clearHistory();
@@ -30169,7 +30264,7 @@
     method public void findAllAsync(java.lang.String);
     method public void findNext(boolean);
     method public void flingScroll(int, int);
-    method public void freeMemory();
+    method public deprecated void freeMemory();
     method public android.net.http.SslCertificate getCertificate();
     method public int getContentHeight();
     method public android.graphics.Bitmap getFavicon();
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/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 3e4795c..bf2a1e4 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -65,7 +65,7 @@
 
     // when adding one of these:
     //  - increment _NUM_OP
-    //  - add rows to sOpToSwitch, sOpNames, sOpPerms
+    //  - add rows to sOpToSwitch, sOpNames, sOpPerms, sOpDefaultMode
     //  - add descriptive strings to Settings/res/values/arrays.xml
     //  - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
 
@@ -315,6 +315,55 @@
     };
 
     /**
+     * This specifies the default mode for each operation.
+     */
+    private static int[] sOpDefaultMode = new int[] {
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+    };
+
+    /**
      * Retrieve the op switch that controls the given operation.
      * @hide
      */
@@ -339,6 +388,14 @@
     }
 
     /**
+     * Retrieve the default mode for the operation.
+     * @hide
+     */
+    public static int opToDefaultMode(int op) {
+        return sOpDefaultMode[op];
+    }
+
+    /**
      * Class holding all of the operation information associated with an app.
      * @hide
      */
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/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 0a1d3f9a..9a258dc 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1573,8 +1573,10 @@
          */
         if (mContext == null) {
             mContext = context;
-            mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService(
-                    Context.APP_OPS_SERVICE);
+            if (context != null) {
+                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
+                        Context.APP_OPS_SERVICE);
+            }
             mMyUid = Process.myUid();
             if (info != null) {
                 setReadPermission(info.readPermission);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f250029..5618cab 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2316,8 +2316,7 @@
         }
 
         @Override
-        public void close() throws IOException {
-            super.close();
+        public void releaseResources() {
             if (!mProviderReleased) {
                 ContentResolver.this.releaseProvider(mContentProvider);
                 mProviderReleased = true;
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..a2faf09 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
@@ -341,6 +415,14 @@
      * platform opaque YUV/RGB streams to the GPU or video
      * encoders. Listed as width, height
      * </p>
+     * <p>
+     * The actual supported resolution list may be limited by
+     * consumer end points for different use cases. For example, for
+     * recording use case, the largest supported resolution may be
+     * limited by max supported size from encoder, for preview use
+     * case, the largest supported resolution may be limited by max
+     * resolution SurfaceTexture/SurfaceView can support.
+     * </p>
      */
     public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
             new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
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/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 40a3612..d0feaa3 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -255,6 +255,10 @@
         return mRequiresDeviceUnlock;
     }
 
+    public String getDescription() {
+        return mDescription;
+    }
+
     public CharSequence loadLabel(PackageManager pm) {
         return mService.loadLabel(pm);
     }
@@ -287,6 +291,11 @@
             Log.e(TAG, "AID " + aid + " is not correctly formatted.");
             return false;
         }
+        // Minimum AID length is 5 bytes, 10 hex chars
+        if (aidLength < 10) {
+            Log.e(TAG, "AID " + aid + " is shorter than 5 bytes.");
+            return false;
+        }
         return true;
     }
 
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 579971d..5a49b98 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -564,7 +564,11 @@
     @Override
     public void close() throws IOException {
         if (mWrapped != null) {
-            mWrapped.close();
+            try {
+                mWrapped.close();
+            } finally {
+                releaseResources();
+            }
         } else {
             closeWithStatus(Status.OK, null);
         }
@@ -579,7 +583,11 @@
      */
     public void closeWithError(String msg) throws IOException {
         if (mWrapped != null) {
-            mWrapped.closeWithError(msg);
+            try {
+                mWrapped.closeWithError(msg);
+            } finally {
+                releaseResources();
+            }
         } else {
             if (msg == null) {
                 throw new IllegalArgumentException("Message must not be null");
@@ -588,17 +596,22 @@
         }
     }
 
-    private void closeWithStatus(int status, String msg) throws IOException {
-        if (mWrapped != null) {
-            mWrapped.closeWithStatus(status, msg);
-        } else {
-            if (mClosed) return;
-            mClosed = true;
-            mGuard.close();
-            // Status MUST be sent before closing actual descriptor
-            writeCommStatusAndClose(status, msg);
-            IoUtils.closeQuietly(mFd);
-        }
+    private void closeWithStatus(int status, String msg) {
+        if (mClosed) return;
+        mClosed = true;
+        mGuard.close();
+        // Status MUST be sent before closing actual descriptor
+        writeCommStatusAndClose(status, msg);
+        IoUtils.closeQuietly(mFd);
+        releaseResources();
+    }
+
+    /**
+     * Called when the fd is being closed, for subclasses to release any other resources
+     * associated with it, such as acquired providers.
+     * @hide
+     */
+    public void releaseResources() {
     }
 
     private byte[] getOrCreateStatusBuffer() {
@@ -793,6 +806,9 @@
 
     @Override
     protected void finalize() throws Throwable {
+        if (mWrapped != null) {
+            releaseResources();
+        }
         if (mGuard != null) {
             mGuard.warnIfOpen();
         }
@@ -822,7 +838,11 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         if (mWrapped != null) {
-            mWrapped.writeToParcel(out, flags);
+            try {
+                mWrapped.writeToParcel(out, flags);
+            } finally {
+                releaseResources();
+            }
         } else {
             out.writeFileDescriptor(mFd);
             if (mCommFd != null) {
@@ -832,11 +852,8 @@
                 out.writeInt(0);
             }
             if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
-                try {
-                    // Not a real close, so emit no status
-                    closeWithStatus(Status.SILENCE, null);
-                } catch (IOException e) {
-                }
+                // Not a real close, so emit no status
+                closeWithStatus(Status.SILENCE, null);
             }
         }
     }
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index d2ae5e6f..4e839c6 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -19,6 +19,7 @@
 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;
@@ -31,12 +32,12 @@
  */
 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);
 
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/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index d889353..efe6b15 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -373,27 +373,208 @@
 
         // North America
 
-        /** North America Letter media size: 8.5" x 11" */
+        /** North America Letter media size: 8.5" x 11" (279mm x 216mm) */
         public static final MediaSize NA_LETTER =
                 new MediaSize("NA_LETTER", "android", R.string.mediaSize_na_letter, 8500, 11000);
-        /** North America Government-Letter media size: 8.0" x 10.5" */
+        /** North America Government-Letter media size: 8.0" x 10.5" (203mm x 267mm) */
         public static final MediaSize NA_GOVT_LETTER =
                 new MediaSize("NA_GOVT_LETTER", "android",
                         R.string.mediaSize_na_gvrnmt_letter, 8000, 10500);
-        /** North America Legal media size: 8.5" x 14" */
+        /** North America Legal media size: 8.5" x 14" (216mm x 356mm) */
         public static final MediaSize NA_LEGAL =
                 new MediaSize("NA_LEGAL", "android", R.string.mediaSize_na_legal, 8500, 14000);
-        /** North America Junior Legal media size: 8.0" x 5.0" */
+        /** North America Junior Legal media size: 8.0" x 5.0" (203mm × 127mm) */
         public static final MediaSize NA_JUNIOR_LEGAL =
                 new MediaSize("NA_JUNIOR_LEGAL", "android",
                         R.string.mediaSize_na_junior_legal, 8000, 5000);
-        /** North America Ledger media size: 17" x 11" */
+        /** North America Ledger media size: 17" x 11" (432mm × 279mm) */
         public static final MediaSize NA_LEDGER =
                 new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
-        /** North America Tabloid media size: 11" x 17" */
+        /** North America Tabloid media size: 11" x 17" (279mm × 432mm) */
         public static final MediaSize NA_TBLOID =
                 new MediaSize("NA_TABLOID", "android",
                         R.string.mediaSize_na_tabloid, 11000, 17000);
+        /** North America Index Card 3x5 media size: 3" x 5" (76mm x 127mm) */
+        public static final MediaSize NA_INDEX_3X5 =
+                new MediaSize("NA_INDEX_3X5", "android",
+                        R.string.mediaSize_na_index_3x5, 3000, 5000);
+        /** North America Index Card 4x6 media size: 4" x 6" (102mm x 152mm) */
+        public static final MediaSize NA_INDEX_4X6 =
+                new MediaSize("NA_INDEX_4X6", "android",
+                        R.string.mediaSize_na_index_4x6, 4000, 6000);
+        /** North America Index Card 5x8 media size: 5" x 8" (127mm x 203mm) */
+        public static final MediaSize NA_INDEX_5X8 =
+                new MediaSize("NA_INDEX_5X8", "android",
+                        R.string.mediaSize_na_index_5x8, 5000, 8000);
+        /** North America Monarch media size: 7.25" x 10.5" (184mm x 267mm) */
+        public static final MediaSize NA_MONARCH =
+                new MediaSize("NA_MONARCH", "android",
+                        R.string.mediaSize_na_monarch, 7250, 10500);
+        /** North America Quarto media size: 8" x 10" (203mm x 254mm) */
+        public static final MediaSize NA_QUARTO =
+                new MediaSize("NA_QUARTO", "android",
+                        R.string.mediaSize_na_quarto, 8000, 10000);
+        /** North America Foolscap media size: 8" x 13" (203mm x 330mm) */
+        public static final MediaSize NA_FOOLSCAP =
+                new MediaSize("NA_FOOLSCAP", "android",
+                        R.string.mediaSize_na_foolscap, 8000, 13000);
+
+        // Chinese
+
+        /** Chinese ROC 8K media size: 270mm x 390mm (10.629" x 15.3543") */
+        public static final MediaSize ROC_8K =
+                new MediaSize("ROC_8K", "android",
+                        R.string.mediaSize_chinese_roc_8k, 10629, 15354);
+        /** Chinese ROC 16K media size: 195mm x 270mm (7.677" x 10.629") */
+        public static final MediaSize ROC_16K =
+                new MediaSize("ROC_16K", "android",
+                        R.string.mediaSize_chinese_roc_16k, 7677, 10629);
+
+        /** Chinese PRC 1 media size: 102mm x 165mm (4.015" x 6.496") */
+        public static final MediaSize PRC_1 =
+                new MediaSize("PRC_1", "android",
+                        R.string.mediaSize_chinese_prc_1, 4015, 6496);
+        /** Chinese PRC 2 media size: 102mm x 176mm (4.015" x 6.929") */
+        public static final MediaSize PRC_2 =
+                new MediaSize("PRC_2", "android",
+                        R.string.mediaSize_chinese_prc_2, 4015, 6929);
+        /** Chinese PRC 3 media size: 125mm x 176mm (4.921" x 6.929") */
+        public static final MediaSize PRC_3 =
+                new MediaSize("PRC_3", "android",
+                        R.string.mediaSize_chinese_prc_3, 4921, 6929);
+        /** Chinese PRC 4 media size: 110mm x 208mm (4.330" x 8.189") */
+        public static final MediaSize PRC_4 =
+                new MediaSize("PRC_4", "android",
+                        R.string.mediaSize_chinese_prc_4, 4330, 8189);
+        /** Chinese PRC 5 media size: 110mm x 220mm (4.330" x 8.661") */
+        public static final MediaSize PRC_5 =
+                new MediaSize("PRC_5", "android",
+                        R.string.mediaSize_chinese_prc_5, 4330, 8661);
+        /** Chinese PRC 6 media size: 120mm x 320mm (4.724" x 12.599") */
+        public static final MediaSize PRC_6 =
+                new MediaSize("PRC_6", "android",
+                        R.string.mediaSize_chinese_prc_6, 4724, 12599);
+        /** Chinese PRC 7 media size: 160mm x 230mm (6.299" x 9.055") */
+        public static final MediaSize PRC_7 =
+                new MediaSize("PRC_7", "android",
+                        R.string.mediaSize_chinese_prc_7, 6299, 9055);
+        /** Chinese PRC 8 media size: 120mm x 309mm (4.724" x 12.165") */
+        public static final MediaSize PRC_8 =
+                new MediaSize("PRC_8", "android",
+                        R.string.mediaSize_chinese_prc_8, 4724, 12165);
+        /** Chinese PRC 9 media size: 229mm x 324mm (9.016" x 12.756") */
+        public static final MediaSize PRC_9 =
+                new MediaSize("PRC_9", "android",
+                        R.string.mediaSize_chinese_prc_9, 9016, 12756);
+        /** Chinese PRC 10 media size: 324mm x 458mm (12.756" x 18.032") */
+        public static final MediaSize PRC_10 =
+                new MediaSize("PRC_10", "android",
+                        R.string.mediaSize_chinese_prc_10, 12756, 18032);
+
+        /** Chinese PRC 16k media size: 146mm x 215mm (5.749" x 8.465") */
+        public static final MediaSize PRC_16k =
+                new MediaSize("PRC_16k", "android",
+                        R.string.mediaSize_chinese_prc_16k, 5749, 8465);
+        /** Chinese Pa Kai media size: 267mm x 389mm (10.512" x 15.315") */
+        public static final MediaSize OM_PA_KAI =
+                new MediaSize("OM_PA_KAI", "android",
+                        R.string.mediaSize_chinese_om_pa_kai, 10512, 15315);
+        /** Chinese Dai Pa Kai media size: 275mm x 395mm (10.827" x 15.551") */
+        public static final MediaSize OM_DAI_PA_KAI =
+                new MediaSize("OM_DAI_PA_KAI", "android",
+                        R.string.mediaSize_chinese_om_dai_pa_kai, 10827, 15551);
+        /** Chinese Jurro Ku Kai media size: 198mm x 275mm (7.796" x 10.827") */
+        public static final MediaSize OM_JUURO_KU_KAI =
+                new MediaSize("OM_JUURO_KU_KAI", "android",
+                        R.string.mediaSize_chinese_om_jurro_ku_kai, 7796, 10827);
+
+        // Japanese
+
+        /** Japanese JIS B10 media size: 32mm x 45mm (1.259" x 1.772") */
+        public static final MediaSize JIS_B10 =
+                new MediaSize("JIS_B10", "android",
+                        R.string.mediaSize_japanese_jis_b10, 1259, 1772);
+        /** Japanese JIS B9 media size: 45mm x 64mm (1.772" x 2.52") */
+        public static final MediaSize JIS_B9 =
+                new MediaSize("JIS_B9", "android",
+                        R.string.mediaSize_japanese_jis_b9, 1772, 2520);
+        /** Japanese JIS B8 media size: 64mm x 91mm (2.52" x 3.583") */
+        public static final MediaSize JIS_B8 =
+                new MediaSize("JIS_B8", "android",
+                        R.string.mediaSize_japanese_jis_b8, 2520, 3583);
+        /** Japanese JIS B7 media size: 91mm x 128mm (3.583" x 5.049") */
+        public static final MediaSize JIS_B7 =
+                new MediaSize("JIS_B7", "android",
+                        R.string.mediaSize_japanese_jis_b7, 3583, 5049);
+        /** Japanese JIS B6 media size: 128mm x 182mm (5.049" x 7.165") */
+        public static final MediaSize JIS_B6 =
+                new MediaSize("JIS_B6", "android",
+                        R.string.mediaSize_japanese_jis_b6, 5049, 7165);
+        /** Japanese JIS B5 media size: 182mm x 257mm (7.165" x 10.118") */
+        public static final MediaSize JIS_B5 =
+                new MediaSize("JIS_B5", "android",
+                        R.string.mediaSize_japanese_jis_b5, 7165, 10118);
+        /** Japanese JIS B4 media size: 257mm x 364mm (10.118" x 14.331") */
+        public static final MediaSize JIS_B4 =
+                new MediaSize("JIS_B4", "android",
+                        R.string.mediaSize_japanese_jis_b4, 10118, 14331);
+        /** Japanese JIS B3 media size: 364mm x 515mm (14.331" x 20.276") */
+        public static final MediaSize JIS_B3 =
+                new MediaSize("JIS_B3", "android",
+                        R.string.mediaSize_japanese_jis_b3, 14331, 20276);
+        /** Japanese JIS B2 media size: 515mm x 728mm (20.276" x 28.661") */
+        public static final MediaSize JIS_B2 =
+                new MediaSize("JIS_B2", "android",
+                        R.string.mediaSize_japanese_jis_b2, 20276, 28661);
+        /** Japanese JIS B1 media size: 728mm x 1030mm (28.661" x 40.551") */
+        public static final MediaSize JIS_B1 =
+                new MediaSize("JIS_B1", "android",
+                        R.string.mediaSize_japanese_jis_b1, 28661, 40551);
+        /** Japanese JIS B0 media size: 1030mm x 1456mm (40.551" x 57.323") */
+        public static final MediaSize JIS_B0 =
+                new MediaSize("JIS_B0", "android",
+                        R.string.mediaSize_japanese_jis_b0, 40551, 57323);
+
+        /** Japanese JIS Exec media size: 216mm x 330mm (8.504" x 12.992") */
+        public static final MediaSize JIS_EXEC =
+                new MediaSize("JIS_EXEC", "android",
+                        R.string.mediaSize_japanese_jis_exec, 8504, 12992);
+
+        /** Japanese Chou4 media size: 90mm x 205mm (3.543" x 8.071") */
+        public static final MediaSize JPN_CHOU4 =
+                new MediaSize("JPN_CHOU4", "android",
+                        R.string.mediaSize_japanese_chou4, 3543, 8071);
+        /** Japanese Chou3 media size: 120mm x 235mm (4.724" x 9.252") */
+        public static final MediaSize JPN_CHOU3 =
+                new MediaSize("JPN_CHOU3", "android",
+                        R.string.mediaSize_japanese_chou3, 4724, 9252);
+        /** Japanese Chou2 media size: 111.1mm x 146mm (4.374" x 5.748") */
+        public static final MediaSize JPN_CHOU2 =
+                new MediaSize("JPN_CHOU2", "android",
+                        R.string.mediaSize_japanese_chou2, 4374, 5748);
+
+        /** Japanese Hagaki media size: 100mm x 148mm (3.937" x 5.827") */
+        public static final MediaSize JPN_HAGAKI =
+                new MediaSize("JPN_HAGAKI", "android",
+                        R.string.mediaSize_japanese_hagaki, 3937, 5827);
+        /** Japanese Oufuku media size: 148mm x 200mm (5.827" x 7.874") */
+        public static final MediaSize JPN_OUFUKU =
+                new MediaSize("JPN_OUFUKU", "android",
+                        R.string.mediaSize_japanese_oufuku, 5827, 7874);
+
+        /** Japanese Kahu media size: 240mm x 322.1mm (9.449" x 12.681") */
+        public static final MediaSize JPN_KAHU =
+                new MediaSize("JPN_KAHU", "android",
+                        R.string.mediaSize_japanese_kahu, 9449, 12681);
+        /** Japanese Kaku2 media size: 240mm x 332mm (9.449" x 13.071") */
+        public static final MediaSize JPN_KAKU2 =
+                new MediaSize("JPN_KAKU2", "android",
+                        R.string.mediaSize_japanese_kaku2, 9449, 13071);
+
+        /** Japanese You4 media size: 105mm x 235mm (4.134" x 9.252") */
+        public static final MediaSize JPN_YOU4 =
+                new MediaSize("JPN_YOU4", "android",
+                        R.string.mediaSize_japanese_you4, 4134, 9252);
 
         private final String mId;
         /**@hide */
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 10cc771..5429155 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -36,7 +36,6 @@
 
 import libcore.io.IoUtils;
 
-import java.io.File;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -114,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) {
@@ -148,7 +147,7 @@
         return Collections.emptyList();
     }
 
-    void cancelPrintJob(int printJobId) {
+    void cancelPrintJob(PrintJobId printJobId) {
         try {
             mService.cancelPrintJob(printJobId, mAppId, mUserId);
         } catch (RemoteException re) {
@@ -157,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.
      *
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/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 c1c826c..6c6635d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4355,6 +4355,12 @@
         public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
 
         /**
+         * Specifies the package name currently configured to be the primary sms application
+         * @hide
+         */
+        public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
+
+        /**
          * Name of a package that the current user has explicitly allowed to see all of that
          * user's notifications.
          *
@@ -4365,6 +4371,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..5f948bd 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -41,7 +41,6 @@
     private static boolean DBG = Transition.DBG && false;
 
     private static final String LOG_TAG = "Fade";
-    private static final String PROPNAME_ALPHA = "android:fade:alpha";
     private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
     private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
 
@@ -90,7 +89,11 @@
             }
             return null;
         }
-        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
+        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "transitionAlpha", startAlpha,
+                endAlpha);
+        if (DBG) {
+            Log.d(LOG_TAG, "Created animator " + anim);
+        }
         if (listener != null) {
             anim.addListener(listener);
             anim.addPauseListener(listener);
@@ -99,8 +102,6 @@
     }
 
     private void captureValues(TransitionValues transitionValues) {
-        float alpha = transitionValues.view.getAlpha();
-        transitionValues.values.put(PROPNAME_ALPHA, alpha);
         int[] loc = new int[2];
         transitionValues.view.getLocationOnScreen(loc);
         transitionValues.values.put(PROPNAME_SCREEN_X, loc[0]);
@@ -113,29 +114,6 @@
         captureValues(transitionValues);
     }
 
-
-    @Override
-    public void captureEndValues(TransitionValues transitionValues) {
-        super.captureEndValues(transitionValues);
-    }
-
-    @Override
-    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-            TransitionValues endValues) {
-        Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
-        if (animator == null && startValues != null && endValues != null) {
-            boolean endVisible = isVisible(endValues);
-            final View endView = endValues.view;
-            float endAlpha = endView.getAlpha();
-            float startAlpha = (Float) startValues.values.get(PROPNAME_ALPHA);
-            if ((endVisible && startAlpha < endAlpha && (mFadingMode & Fade.IN) != 0) ||
-                    (!endVisible && startAlpha > endAlpha && (mFadingMode & Fade.OUT) != 0)) {
-                animator = createAnimation(endView, startAlpha, endAlpha, null);
-            }
-        }
-        return animator;
-    }
-
     @Override
     public Animator onAppear(ViewGroup sceneRoot,
             TransitionValues startValues, int startVisibility,
@@ -146,14 +124,40 @@
         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);
-        }
-        return createAnimation(endView, endView.getAlpha(), 1, null);
+        endView.setTransitionAlpha(0);
+        TransitionListener transitionListener = new TransitionListenerAdapter() {
+            boolean mCanceled = false;
+            float mPausedAlpha;
+
+            @Override
+            public void onTransitionCancel(Transition transition) {
+                endView.setTransitionAlpha(1);
+                mCanceled = true;
+            }
+
+            @Override
+            public void onTransitionEnd(Transition transition) {
+                if (!mCanceled) {
+                    endView.setTransitionAlpha(1);
+                }
+            }
+
+            @Override
+            public void onTransitionPause(Transition transition) {
+                mPausedAlpha = endView.getTransitionAlpha();
+                endView.setTransitionAlpha(1);
+            }
+
+            @Override
+            public void onTransitionResume(Transition transition) {
+                endView.setTransitionAlpha(mPausedAlpha);
+            }
+        };
+        addListener(transitionListener);
+        return createAnimation(endView, 0, 1, null);
     }
 
     @Override
@@ -204,7 +208,7 @@
             overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
             sceneRoot.getOverlay().add(overlayView);
             // TODO: add automatic facility to Visibility superclass for keeping views around
-            final float startAlpha = view.getAlpha();
+            final float startAlpha = 1;
             float endAlpha = 0;
             final View finalView = view;
             final View finalOverlayView = overlayView;
@@ -213,7 +217,7 @@
             final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    finalView.setAlpha(startAlpha);
+                    finalView.setTransitionAlpha(startAlpha);
                     // TODO: restore view offset from overlay repositioning
                     if (finalViewToKeep != null) {
                         finalViewToKeep.setVisibility(finalVisibility);
@@ -244,7 +248,7 @@
             // VISIBLE for the duration of the transition
             viewToKeep.setVisibility((View.VISIBLE));
             // TODO: add automatic facility to Visibility superclass for keeping views around
-            final float startAlpha = view.getAlpha();
+            final float startAlpha = 1;
             float endAlpha = 0;
             final View finalView = view;
             final View finalOverlayView = overlayView;
@@ -259,8 +263,8 @@
                     if (finalViewToKeep != null && !mCanceled) {
                         finalViewToKeep.setVisibility(finalVisibility);
                     }
-                    mPausedAlpha = finalView.getAlpha();
-                    finalView.setAlpha(startAlpha);
+                    mPausedAlpha = finalView.getTransitionAlpha();
+                    finalView.setTransitionAlpha(startAlpha);
                 }
 
                 @Override
@@ -268,21 +272,21 @@
                     if (finalViewToKeep != null && !mCanceled) {
                         finalViewToKeep.setVisibility(View.VISIBLE);
                     }
-                    finalView.setAlpha(mPausedAlpha);
+                    finalView.setTransitionAlpha(mPausedAlpha);
                 }
 
                 @Override
                 public void onAnimationCancel(Animator animation) {
                     mCanceled = true;
                     if (mPausedAlpha >= 0) {
-                        finalView.setAlpha(mPausedAlpha);
+                        finalView.setTransitionAlpha(mPausedAlpha);
                     }
                 }
 
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     if (!mCanceled) {
-                        finalView.setAlpha(startAlpha);
+                        finalView.setTransitionAlpha(startAlpha);
                     }
                     // TODO: restore view offset from overlay repositioning
                     if (finalViewToKeep != null && !mCanceled) {
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 2fb32aa..4a99153 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -353,7 +353,7 @@
                 if (endValues.viewValues.get(view) != null) {
                     end = endValues.viewValues.get(view);
                     endCopy.remove(view);
-                } else {
+                } else if (id != View.NO_ID) {
                     end = endValues.idValues.get(id);
                     View removeView = null;
                     for (View viewToRemove : endCopy.keySet()) {
@@ -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);
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 727a98d..44ca4e5 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -349,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 transitionClone = transition.clone();
-//            sceneChangeSetup(sceneRoot, transitionClone);
-//            Scene.setCurrentScene(sceneRoot, null);
-//            sceneChangeRunTransition(sceneRoot, transitionClone);
-//        }
+        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/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index f72b36e..6fdd309 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -354,7 +354,7 @@
         clone.mTransitions = new ArrayList<Transition>();
         int numTransitions = mTransitions.size();
         for (int i = 0; i < numTransitions; ++i) {
-            clone.mTransitions.add((Transition) mTransitions.get(i).clone());
+            clone.addTransition((Transition) mTransitions.get(i).clone());
         }
         return clone;
     }
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index a0d39ca..f36c78f 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -130,7 +130,7 @@
     private float mFocusX;
     private float mFocusY;
 
-    private boolean mDoubleTapScales;
+    private boolean mQuickScaleEnabled;
 
     private float mCurrSpan;
     private float mPrevSpan;
@@ -307,7 +307,7 @@
         final int action = event.getActionMasked();
 
         // Forward the event to check for double tap gesture
-        if (mDoubleTapScales) {
+        if (mQuickScaleEnabled) {
             mGestureDetector.onTouchEvent(event);
         }
 
@@ -456,8 +456,8 @@
      * @param scales true to enable quick scaling, false to disable
      */
     public void setQuickScaleEnabled(boolean scales) {
-        mDoubleTapScales = scales;
-        if (mDoubleTapScales && mGestureDetector == null) {
+        mQuickScaleEnabled = scales;
+        if (mQuickScaleEnabled && mGestureDetector == null) {
             GestureDetector.SimpleOnGestureListener gestureListener =
                     new GestureDetector.SimpleOnGestureListener() {
                         @Override
@@ -472,6 +472,14 @@
         }
     }
 
+  /**
+   * Return whether the quick scale gesture, in which the user performs a double tap followed by a
+   * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}.
+   */
+    public boolean isQuickScaleEnabled() {
+        return mQuickScaleEnabled;
+    }
+
     /**
      * Returns {@code true} if a scale gesture is in progress.
      */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a5db6ee..4680e76 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2894,6 +2894,13 @@
          */
         @ViewDebug.ExportedProperty
         float mAlpha = 1f;
+
+        /**
+         * The opacity of the view as manipulated by the Fade transition. This is a hidden
+         * property only used by transitions, which is composited with the other alpha
+         * values to calculate the final visual alpha value.
+         */
+        float mTransitionAlpha = 1f;
     }
 
     TransformationInfo mTransformationInfo;
@@ -5335,7 +5342,8 @@
                 View view = (View) current;
                 // We have attach info so this view is attached and there is no
                 // need to check whether we reach to ViewRootImpl on the way up.
-                if (view.getAlpha() <= 0 || view.getVisibility() != VISIBLE) {
+                if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 ||
+                        view.getVisibility() != VISIBLE) {
                     return false;
                 }
                 current = view.mParent;
@@ -9786,7 +9794,7 @@
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 invalidateViewProperty(true, false);
                 if (mDisplayList != null) {
-                    mDisplayList.setAlpha(alpha);
+                    mDisplayList.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -9813,7 +9821,7 @@
             } else {
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 if (mDisplayList != null) {
-                    mDisplayList.setAlpha(alpha);
+                    mDisplayList.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -9821,6 +9829,51 @@
     }
 
     /**
+     * This property is hidden and intended only for use by the Fade transition, which
+     * animates it to produce a visual translucency that does not side-effect (or get
+     * affected by) the real alpha property. This value is composited with the other
+     * alpha value (and the AlphaAnimation value, when that is present) to produce
+     * a final visual translucency result, which is what is passed into the DisplayList.
+     *
+     * @hide
+     */
+    public void setTransitionAlpha(float alpha) {
+        ensureTransformationInfo();
+        if (mTransformationInfo.mTransitionAlpha != alpha) {
+            mTransformationInfo.mTransitionAlpha = alpha;
+            mPrivateFlags &= ~PFLAG_ALPHA_SET;
+            invalidateViewProperty(true, false);
+            if (mDisplayList != null) {
+                mDisplayList.setAlpha(getFinalAlpha());
+            }
+        }
+    }
+
+    /**
+     * Calculates the visual alpha of this view, which is a combination of the actual
+     * alpha value and the transitionAlpha value (if set).
+     */
+    private float getFinalAlpha() {
+        if (mTransformationInfo != null) {
+            return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha;
+        }
+        return 1;
+    }
+
+    /**
+     * This property is hidden and intended only for use by the Fade transition, which
+     * animates it to produce a visual translucency that does not side-effect (or get
+     * affected by) the real alpha property. This value is composited with the other
+     * alpha value (and the AlphaAnimation value, when that is present) to produce
+     * a final visual translucency result, which is what is passed into the DisplayList.
+     *
+     * @hide
+     */
+    public float getTransitionAlpha() {
+        return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1;
+    }
+
+    /**
      * Top position of this view relative to its parent.
      *
      * @return The top of this view, in pixels.
@@ -10913,7 +10966,7 @@
     @ViewDebug.ExportedProperty(category = "drawing")
     public boolean isOpaque() {
         return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK &&
-                ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1.0f) >= 1.0f);
+                getFinalAlpha() >= 1.0f;
     }
 
     /**
@@ -13868,7 +13921,7 @@
                 }
             }
             if (mTransformationInfo != null) {
-                alpha *= mTransformationInfo.mAlpha;
+                alpha *= getFinalAlpha();
                 if (alpha < 1) {
                     final int multipliedAlpha = (int) (255 * alpha);
                     if (onSetAlpha(multipliedAlpha)) {
@@ -14057,8 +14110,8 @@
             }
         }
 
-        float alpha = useDisplayListProperties ? 1 : getAlpha();
-        if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() ||
+        float alpha = useDisplayListProperties ? 1 : (getAlpha() * getTransitionAlpha());
+        if (transformToApply != null || alpha < 1 ||  !hasIdentityMatrix() ||
                 (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) {
             if (transformToApply != null || !childHasIdentityMatrix) {
                 int transX = 0;
@@ -14115,7 +14168,7 @@
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
                         if (useDisplayListProperties) {
-                            displayList.setAlpha(alpha * getAlpha());
+                            displayList.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                         } else  if (layerType == LAYER_TYPE_NONE) {
                             final int scrollX = hasDisplayList ? 0 : sx;
                             final int scrollY = hasDisplayList ? 0 : sy;
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index ad8b51d..f9298ea 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -990,10 +990,10 @@
             mStart = false;
             if (mDataCopy != null) {
                 mData = mDataCopy;
+                mAccess.mData.clear();
+                mAccess.mSize = 0;
             }
             mDataCopy = null;
-            mAccess.mData.clear();
-            mAccess.mSize = 0;
         }
 
         int size() {
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 21b0578..aa57423 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -238,9 +238,10 @@
     * @param totalQuota The total quota for all origins, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onExceededDatabaseQuota(String url, String databaseIdentifier,
             long quota, long estimatedDatabaseSize, long totalQuota,
             WebStorage.QuotaUpdater quotaUpdater) {
@@ -263,9 +264,10 @@
     * @param quota the current maximum Application Cache size, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
             WebStorage.QuotaUpdater quotaUpdater) {
         quotaUpdater.updateQuota(quota);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 7a38a16..98ef66e 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -33,14 +33,17 @@
     /**
      * Enum for controlling the layout of html.
      * <ul>
-     *   <li>NORMAL means no rendering changes.</li>
+     *   <li>NORMAL means no rendering changes. This is the recommended choice for maximum
+     *       compatibility across different platforms and Android versions.</li>
      *   <li>SINGLE_COLUMN moves all content into one column that is the width of the
      *       view.</li>
-     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible.</li>
+     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible. Only use
+     *       this for API levels prior to {@link android.os.Build.VERSION_CODES#KITKAT}.</li>
      *   <li>TEXT_AUTOSIZING boosts font size of paragraphs based on heuristics to make
      *       the text readable when viewing a wide-viewport layout in the overview mode.
      *       It is recommended to enable zoom support {@link #setSupportZoom} when
-     *       using this mode.</li>
+     *       using this mode. Supported from API level
+     *       {@link android.os.Build.VERSION_CODES#KITKAT}</li>
      * </ul>
      */
     // XXX: These must match LayoutAlgorithm in Settings.h in WebCore.
@@ -51,10 +54,11 @@
          */
         @Deprecated
         SINGLE_COLUMN,
-        NARROW_COLUMNS,
         /**
-         * @hide
+         * @deprecated This algorithm is now obsolete.
          */
+        @Deprecated
+        NARROW_COLUMNS,
         TEXT_AUTOSIZING
     }
 
@@ -510,7 +514,10 @@
      * and {@link #setUseWideViewPort} can be used.
      *
      * @param zoom the zoom density
+     * @deprecated This method is no longer supported, see the function documentation for
+     *             recommended alternatives.
      */
+    @Deprecated
     public void setDefaultZoom(ZoomDensity zoom) {
         throw new MustOverrideException();
     }
@@ -523,6 +530,7 @@
      *
      * @return the zoom density
      * @see #setDefaultZoom
+     * @deprecated Will only return the default value.
      */
     public ZoomDensity getDefaultZoom() {
         throw new MustOverrideException();
@@ -1059,10 +1067,13 @@
      *
      * @param databasePath a path to the directory where databases should be
      *                     saved.
+     * @deprecated Database paths are managed by the implementation and calling this method
+     *             will have no effect.
      */
     // This will update WebCore when the Sync runs in the C++ side.
     // Note that the WebCore Database Tracker only allows the path to be set
     // once.
+    @Deprecated
     public synchronized void setDatabasePath(String databasePath) {
         throw new MustOverrideException();
     }
@@ -1161,7 +1172,9 @@
      *
      * @return the String path to the database storage API databases
      * @see #setDatabasePath
+     * @deprecated Database paths are managed by the implementation this method is obsolete.
      */
+    @Deprecated
     public synchronized String getDatabasePath() {
         throw new MustOverrideException();
     }
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 7d9373c..3bfe9cf 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -41,12 +41,9 @@
      * See
      * {@link WebChromeClient#onExceededDatabaseQuota} and
      * {@link WebChromeClient#onReachedMaxAppCacheSize}.
+     * @deprecated This class is obsolete and no longer used.
      */
-    // We primarily want this to allow us to call back the sleeping WebCore
-    // thread from outside the WebViewCore class (as the native call is
-    // private). It is imperative that the setDatabaseQuota method is
-    // executed after a decision to either allow or deny new quota is made,
-    // otherwise the WebCore thread will remain asleep.
+    @Deprecated
     public interface QuotaUpdater {
         /**
          * Provides a new quota, specified in bytes.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 15331dc..d05bba7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1058,9 +1058,20 @@
      * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and
      * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} inclusive, the
      * picture does not include fixed position elements or scrollable divs.
+     * <p>
+     * Note that from {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} the returned picture
+     * should only be drawn into bitmap-backed Canvas - using any other type of Canvas will involve
+     * additional conversion at a cost in memory and performance. Also the
+     * {@link android.graphics.Picture#createFromStream} and
+     * {@link android.graphics.Picture#writeToStream} methods are not supported on the
+     * returned object.
+     *
+     * @deprecated Use {@link #onDraw} to obtain a bitmap snapshot of the WebView, or
+     * {@link #saveWebArchive} or {@link #exportToPdf} to save the content to a file.
      *
      * @return a picture that captures the current contents of this WebView
      */
+    @Deprecated
     public Picture capturePicture() {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "capturePicture");
@@ -1342,7 +1353,10 @@
     /**
      * Informs this WebView that memory is low so that it can free any available
      * memory.
+     * @deprecated Memory caches are automatically dropped when no longer needed, and in response
+     *             to system memory pressure.
      */
+    @Deprecated
     public void freeMemory() {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "freeMemory");
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index de2be75..0957ab4 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -391,7 +391,7 @@
         mWeekSeperatorLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                 UNSCALED_WEEK_SEPARATOR_LINE_WIDTH, displayMetrics);
 
-        LayoutInflater layoutInflater = (LayoutInflater) mContext
+        LayoutInflater layoutInflater = (LayoutInflater) context
                 .getSystemService(Service.LAYOUT_INFLATER_SERVICE);
         View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
         addView(content);
@@ -874,7 +874,6 @@
         }
         mFirstDayOfWeek = firstDayOfWeek;
         mAdapter.init();
-        mAdapter.notifyDataSetChanged();
         setUpHeader();
     }
 
@@ -937,7 +936,7 @@
     }
 
     private void updateDateTextSize() {
-        TypedArray dateTextAppearance = getContext().obtainStyledAttributes(
+        TypedArray dateTextAppearance = mContext.obtainStyledAttributes(
                 mDateTextAppearanceResId, R.styleable.TextAppearance);
         mDateTextSize = dateTextAppearance.getDimensionPixelSize(
                 R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE);
@@ -1004,7 +1003,7 @@
      */
     private void setUpAdapter() {
         if (mAdapter == null) {
-            mAdapter = new WeeksAdapter(getContext());
+            mAdapter = new WeeksAdapter();
             mAdapter.registerDataSetObserver(new DataSetObserver() {
                 @Override
                 public void onChanged() {
@@ -1333,19 +1332,16 @@
      * </p>
      */
     private class WeeksAdapter extends BaseAdapter implements OnTouchListener {
+        private final Calendar mSelectedDate = Calendar.getInstance();
+        private final GestureDetector mGestureDetector;
 
         private int mSelectedWeek;
 
-        private GestureDetector mGestureDetector;
-
         private int mFocusedMonth;
 
-        private final Calendar mSelectedDate = Calendar.getInstance();
-
         private int mTotalWeekCount;
 
-        public WeeksAdapter(Context context) {
-            mContext = context;
+        public WeeksAdapter() {
             mGestureDetector = new GestureDetector(mContext, new CalendarGestureListener());
             init();
         }
@@ -1360,6 +1356,7 @@
                 || mMaxDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek) {
                 mTotalWeekCount++;
             }
+            notifyDataSetChanged();
         }
 
         /**
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 19cc3c2..e4956dd 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1099,6 +1099,16 @@
     }
 
     @Override
+    public int computeVerticalScrollOffset() {
+        return mCurrentScrollOffset;
+    }
+
+    @Override
+    public int computeVerticalScrollRange() {
+        return mSelectorIndices.length * mSelectorElementHeight;
+    }
+
+    @Override
     public int getSolidColor() {
         return mSolidColor;
     }
diff --git a/core/java/com/android/internal/app/IProcessStats.aidl b/core/java/com/android/internal/app/IProcessStats.aidl
index 047424d..6fadf2f 100644
--- a/core/java/com/android/internal/app/IProcessStats.aidl
+++ b/core/java/com/android/internal/app/IProcessStats.aidl
@@ -22,5 +22,6 @@
 
 interface IProcessStats {
     byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
+    ParcelFileDescriptor getStatsOverTime(long minTime);
     int getCurrentMemoryState();
 }
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index f2eee45..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,6 +68,10 @@
         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);
@@ -84,6 +92,7 @@
         tv.setText("Android " + Build.VERSION.RELEASE);
         tv.setVisibility(View.INVISIBLE);
 
+        mContent.addView(bg);
         mContent.addView(letter, lp);
         mContent.addView(logo, lp);
 
@@ -94,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..1475e2c 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;
@@ -165,7 +166,7 @@
     static final String CSV_SEP = "\t";
 
     // Current version of the parcel format.
-    private static final int PARCEL_VERSION = 11;
+    private static final int PARCEL_VERSION = 12;
     // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
     private static final int MAGIC = 0x50535453;
 
@@ -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);
                     }
                 }
@@ -1073,10 +1076,8 @@
         return table;
     }
 
-    private void writeCompactedLongArray(Parcel out, long[] array) {
-        final int N = array.length;
-        out.writeInt(N);
-        for (int i=0; i<N; i++) {
+    private void writeCompactedLongArray(Parcel out, long[] array, int num) {
+        for (int i=0; i<num; i++) {
             long val = array[i];
             if (val < 0) {
                 Slog.w(TAG, "Time val negative: " + val);
@@ -1093,16 +1094,17 @@
         }
     }
 
-    private void readCompactedLongArray(Parcel in, int version, long[] array) {
+    private void readCompactedLongArray(Parcel in, int version, long[] array, int num) {
         if (version <= 10) {
             in.readLongArray(array);
             return;
         }
-        final int N = in.readInt();
-        if (N != array.length) {
-            throw new RuntimeException("bad array lengths");
+        final int alen = array.length;
+        if (num > alen) {
+            throw new RuntimeException("bad array lengths: got " + num + " array is " + alen);
         }
-        for (int i=0; i<N; i++) {
+        int i;
+        for (i=0; i<num; i++) {
             int val = in.readInt();
             if (val >= 0) {
                 array[i] = val;
@@ -1111,6 +1113,10 @@
                 array[i] = (((long)~val)<<32) | bottom;
             }
         }
+        while (i < alen) {
+            array[i] = 0;
+            i++;
+        }
     }
 
     private void writeCommonString(Parcel out, String name) {
@@ -1200,19 +1206,17 @@
         out.writeInt(mLongs.size());
         out.writeInt(mNextLong);
         for (int i=0; i<(mLongs.size()-1); i++) {
-            writeCompactedLongArray(out, mLongs.get(i));
+            long[] array = mLongs.get(i);
+            writeCompactedLongArray(out, array, array.length);
         }
         long[] lastLongs = mLongs.get(mLongs.size() - 1);
-        for (int i=0; i<mNextLong; i++) {
-            out.writeLong(lastLongs[i]);
-            if (DEBUG) Slog.d(TAG, "Writing last long #" + i + ": " + lastLongs[i]);
-        }
+        writeCompactedLongArray(out, lastLongs, mNextLong);
 
         if (mMemFactor != STATE_NOTHING) {
             mMemFactorDurations[mMemFactor] += now - mStartTime;
             mStartTime = now;
         }
-        writeCompactedLongArray(out, mMemFactorDurations);
+        writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
 
         out.writeInt(NPROC);
         for (int ip=0; ip<NPROC; ip++) {
@@ -1273,23 +1277,25 @@
         return true;
     }
 
-    static byte[] readFully(InputStream stream) throws IOException {
+    static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
         int pos = 0;
-        int avail = stream.available();
-        byte[] data = new byte[avail];
+        final int initialAvail = stream.available();
+        byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
         while (true) {
             int amt = stream.read(data, pos, data.length-pos);
-            //Log.i("foo", "Read " + amt + " bytes at " + pos
-            //        + " of avail " + data.length);
-            if (amt <= 0) {
-                //Log.i("foo", "**** FINISHED READING: pos=" + pos
-                //        + " len=" + data.length);
+            if (DEBUG) Slog.i("foo", "Read " + amt + " bytes at " + pos
+                    + " of avail " + data.length);
+            if (amt < 0) {
+                if (DEBUG) Slog.i("foo", "**** FINISHED READING: pos=" + pos
+                        + " len=" + data.length);
+                outLen[0] = pos;
                 return data;
             }
             pos += amt;
-            avail = stream.available();
-            if (avail > data.length-pos) {
-                byte[] newData = new byte[pos+avail];
+            if (pos >= data.length) {
+                byte[] newData = new byte[pos+16384];
+                if (DEBUG) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
+                        + newData.length);
                 System.arraycopy(data, 0, newData, 0, pos);
                 data = newData;
             }
@@ -1298,9 +1304,10 @@
 
     public void read(InputStream stream) {
         try {
-            byte[] raw = readFully(stream);
+            int[] len = new int[1];
+            byte[] raw = readFully(stream, len);
             Parcel in = Parcel.obtain();
-            in.unmarshall(raw, 0, raw.length);
+            in.unmarshall(raw, 0, len[0]);
             in.setDataPosition(0);
             stream.close();
 
@@ -1355,17 +1362,14 @@
             while (i >= mLongs.size()) {
                 mLongs.add(new long[LONGS_SIZE]);
             }
-            readCompactedLongArray(in, version, mLongs.get(i));
+            readCompactedLongArray(in, version, mLongs.get(i), LONGS_SIZE);
         }
         long[] longs = new long[LONGS_SIZE];
         mNextLong = NEXTLONG;
-        for (int i=0; i<NEXTLONG; i++) {
-            longs[i] = in.readLong();
-            if (DEBUG) Slog.d(TAG, "Reading last long #" + i + ": " + longs[i]);
-        }
+        readCompactedLongArray(in, version, longs, NEXTLONG);
         mLongs.add(longs);
 
-        readCompactedLongArray(in, version, mMemFactorDurations);
+        readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
 
         int NPROC = in.readInt();
         if (NPROC < 0) {
@@ -1666,7 +1670,8 @@
         return ss;
     }
 
-    public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpAll) {
+    public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
+            boolean dumpAll) {
         long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
                 mStartTime, now);
         ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
@@ -1690,7 +1695,7 @@
                     pw.print("  * "); pw.print(pkgName); pw.print(" / ");
                             UserHandle.formatUid(pw, uid); pw.println(":");
                 }
-                if (dumpAll) {
+                if (!dumpSummary || dumpAll) {
                     for (int iproc=0; iproc<NPROCS; iproc++) {
                         ProcessState proc = pkgState.mProcesses.valueAt(iproc);
                         pw.print("      Process ");
@@ -1727,16 +1732,16 @@
                     ServiceState svc = pkgState.mServices.valueAt(isvc);
                     dumpServiceStats(pw, "        ", "          ", "    ", "Running", svc,
                             svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
-                            svc.mRunStartTime, now, totalTime, dumpAll);
+                            svc.mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
                     dumpServiceStats(pw, "        ", "          ", "    ", "Started", svc,
                             svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
-                            svc.mStartedStartTime, now, totalTime, dumpAll);
+                            svc.mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
                     dumpServiceStats(pw, "        ", "          ", "      ", "Bound", svc,
                             svc.mBoundCount, ServiceState.SERVICE_BOUND, svc.mBoundState,
-                            svc.mBoundStartTime, now, totalTime, dumpAll);
+                            svc.mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
                     dumpServiceStats(pw, "        ", "          ", "  ", "Executing", svc,
                             svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
-                            svc.mExecStartTime, now, totalTime, dumpAll);
+                            svc.mExecStartTime, now, totalTime, !dumpSummary || dumpAll);
                     if (dumpAll) {
                         pw.print("        mActive="); pw.println(svc.mActive);
                     }
@@ -1780,8 +1785,12 @@
             }
 
             pw.println();
-            pw.println("Summary:");
-            dumpSummaryLocked(pw, reqPackage, now);
+            if (dumpSummary) {
+                pw.println("Summary:");
+                dumpSummaryLocked(pw, reqPackage, now);
+            } else {
+                dumpTotalsLocked(pw, now);
+            }
         } else {
             pw.println();
             dumpTotalsLocked(pw, now);
@@ -2127,6 +2136,7 @@
         int mNumExcessiveCpu;
 
         boolean mMultiPackage;
+        boolean mDead;
 
         public long mTmpTotalTime;
 
@@ -2230,6 +2240,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 +2293,7 @@
         }
 
         public void makeActive() {
+            ensureNotDead();
             mActive = true;
         }
 
@@ -2279,7 +2302,8 @@
         }
 
         public boolean isInUse() {
-            return mActive || mNumActiveServices > 0 || mNumStartedServices > 0;
+            return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
+                    || mCurState != STATE_NOTHING;
         }
 
         /**
@@ -2315,6 +2339,7 @@
         }
 
         void setState(int state, long now) {
+            ensureNotDead();
             if (mCurState != state) {
                 //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
                 commitStateTime(now);
@@ -2392,6 +2417,7 @@
         }
 
         public void addPss(long pss, long uss, boolean always) {
+            ensureNotDead();
             if (!always) {
                 if (mLastPssState == mCurState && SystemClock.uptimeMillis()
                         < (mLastPssTime+(30*1000))) {
@@ -2453,6 +2479,7 @@
         }
 
         public void reportExcessiveWake(ArrayMap<String, ProcessState> pkgList) {
+            ensureNotDead();
             mCommonProcess.mNumExcessiveWake++;
             if (!mCommonProcess.mMultiPackage) {
                 return;
@@ -2464,6 +2491,7 @@
         }
 
         public void reportExcessiveCpu(ArrayMap<String, ProcessState> pkgList) {
+            ensureNotDead();
             mCommonProcess.mNumExcessiveCpu++;
             if (!mCommonProcess.mMultiPackage) {
                 return;
@@ -2489,9 +2517,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 are contining 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
@@ -2499,7 +2535,7 @@
                 PackageState pkg = mStats.mPackages.get(pkgList.keyAt(index), proc.mUid);
                 if (pkg == null) {
                     throw new IllegalStateException("No existing package "
-                            + pkgList.keyAt(index) + " for multi-proc" + proc.mName);
+                            + pkgList.keyAt(index) + " for multi-proc " + proc.mName);
                 }
                 proc = pkg.mProcesses.get(proc.mName);
                 if (proc == null) {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 969c94ba..7efcb6e 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1639,6 +1639,8 @@
 
         @Override
         public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            TransitionManager.beginDelayedTransition(ActionBarView.this, sTransition);
+
             mExpandedActionView = item.getActionView();
             mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources()));
             mCurrentExpandedItem = item;
@@ -1666,6 +1668,8 @@
 
         @Override
         public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            TransitionManager.beginDelayedTransition(ActionBarView.this, sTransition);
+
             // Do this before detaching the actionview from the hierarchy, in case
             // it needs to dismiss the soft keyboard, etc.
             if (mExpandedActionView instanceof CollapsibleActionView) {
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index f9bb233..9c20de2 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -3,6 +3,7 @@
 #include "BitmapFactory.h"
 #include "NinePatchPeeker.h"
 #include "SkData.h"
+#include "SkFrontBufferedStream.h"
 #include "SkImageDecoder.h"
 #include "SkImageRef_ashmem.h"
 #include "SkImageRef_GlobalPool.h"
@@ -120,7 +121,7 @@
     }
 }
 
-static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
+static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream,
         int sampleSize, bool ditherImage) {
 
     SkImageRef* pr;
@@ -465,13 +466,17 @@
         jobject padding, jobject options) {
 
     jobject bitmap = NULL;
-    SkAutoTUnref<SkStreamRewindable> stream(GetRewindableStream(env, is, storage));
+    SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
 
     if (stream.get()) {
+        // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+        // trying to determine the stream's format. Currently the most is 64, read by
+        // SkImageDecoder_libwebp.
+        // FIXME: Get this number from SkImageDecoder
+        SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64));
+        SkASSERT(bufferedStream.get() != NULL);
         // for now we don't allow purgeable with java inputstreams
-        // FIXME: GetRewindableStream may have made a copy, in which case
-        // purgeable should be allowed.
-        bitmap = doDecode(env, stream, padding, options, false, false);
+        bitmap = doDecode(env, bufferedStream, padding, options, false, false);
     }
     return bitmap;
 }
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index f773f59..da8f083 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -5,18 +5,12 @@
 #include "SkStream.h"
 #include "SkTypes.h"
 #include "Utils.h"
-#include <androidfw/Asset.h>
 
-static jmethodID    gInputStream_resetMethodID;
-static jmethodID    gInputStream_markMethodID;
-static jmethodID    gInputStream_markSupportedMethodID;
 static jmethodID    gInputStream_readMethodID;
 static jmethodID    gInputStream_skipMethodID;
 
-class RewindableJavaStream;
-
 /**
- *  Non-rewindable wrapper for a Java InputStream.
+ *  Wrapper for a Java InputStream.
  */
 class JavaInputStreamAdaptor : public SkStream {
 public:
@@ -64,25 +58,6 @@
     }
 
 private:
-    // Does not override rewind, since a JavaInputStreamAdaptor's interface
-    // does not support rewinding. RewindableJavaStream, which is a friend,
-    // will be able to call this method to rewind.
-    bool doRewind() {
-        JNIEnv* env = fEnv;
-
-        fBytesRead = 0;
-        fIsAtEnd = false;
-
-        env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
-        if (env->ExceptionCheck()) {
-            env->ExceptionDescribe();
-            env->ExceptionClear();
-            SkDebugf("------- reset threw an exception\n");
-            return false;
-        }
-        return true;
-    }
-
     size_t doRead(void* buffer, size_t size) {
         JNIEnv* env = fEnv;
         size_t bytesRead = 0;
@@ -148,9 +123,6 @@
     size_t      fCapacity;
     size_t      fBytesRead;
     bool        fIsAtEnd;
-
-    // Allows access to doRewind and fBytesRead.
-    friend class RewindableJavaStream;
 };
 
 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
@@ -190,123 +162,6 @@
     return adaptor_to_mem_stream(adaptor.get());
 }
 
-/**
- *  Wrapper for a Java InputStream which is rewindable and
- *  has a length.
- */
-class RewindableJavaStream : public SkStreamRewindable {
-public:
-    // RewindableJavaStream takes ownership of adaptor.
-    RewindableJavaStream(JavaInputStreamAdaptor* adaptor, size_t length)
-        : fAdaptor(adaptor)
-        , fLength(length) {
-        SkASSERT(fAdaptor != NULL);
-    }
-
-    virtual ~RewindableJavaStream() {
-        fAdaptor->unref();
-    }
-
-    virtual bool rewind() {
-        return fAdaptor->doRewind();
-    }
-
-    virtual size_t read(void* buffer, size_t size) {
-        return fAdaptor->read(buffer, size);
-    }
-
-    virtual bool isAtEnd() const {
-        return fAdaptor->isAtEnd();
-    }
-
-    virtual size_t getLength() const {
-        return fLength;
-    }
-
-    virtual bool hasLength() const {
-        return true;
-    }
-
-    virtual SkStreamRewindable* duplicate() const {
-        // Duplicating this stream requires rewinding and
-        // reading, which modify this Stream (and could
-        // fail, leaving this one invalid).
-        SkASSERT(false);
-        return NULL;
-    }
-
-private:
-    JavaInputStreamAdaptor* fAdaptor;
-    const size_t            fLength;
-};
-
-static jclass   gByteArrayInputStream_Clazz;
-static jfieldID gCountField;
-static jfieldID gPosField;
-
-/**
- *  If jstream is a ByteArrayInputStream, return its remaining length. Otherwise
- *  return 0.
- */
-static size_t get_length_from_byte_array_stream(JNIEnv* env, jobject jstream) {
-    if (env->IsInstanceOf(jstream, gByteArrayInputStream_Clazz)) {
-        // Return the remaining length, to keep the same behavior of using the rest of the
-        // stream.
-        return env->GetIntField(jstream, gCountField) - env->GetIntField(jstream, gPosField);
-    }
-    return 0;
-}
-
-/**
- *  If jstream is a class that has a length, return it. Otherwise
- *  return 0.
- *  Only checks for a set of subclasses.
- */
-static size_t get_length_if_supported(JNIEnv* env, jobject jstream) {
-    size_t len = get_length_from_byte_array_stream(env, jstream);
-    if (len > 0) {
-        return len;
-    }
-    return 0;
-}
-
-SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream,
-                                        jbyteArray storage) {
-    SkAutoTUnref<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
-    if (NULL == adaptor.get()) {
-        return NULL;
-    }
-
-    const size_t length = get_length_if_supported(env, stream);
-    if (length > 0 && env->CallBooleanMethod(stream, gInputStream_markSupportedMethodID)) {
-        // Set the readLimit for mark to the end of the stream, so it can
-        // be rewound regardless of how much has been read.
-        env->CallVoidMethod(stream, gInputStream_markMethodID, length);
-        // RewindableJavaStream will unref adaptor when it is destroyed.
-        return new RewindableJavaStream(static_cast<JavaInputStreamAdaptor*>(adaptor.detach()),
-                                        length);
-    }
-
-    return adaptor_to_mem_stream(adaptor.get());
-}
-
-static jclass       gAssetInputStream_Clazz;
-static jmethodID    gGetAssetIntMethodID;
-
-android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject jstream) {
-    if (!env->IsInstanceOf(jstream, gAssetInputStream_Clazz)) {
-        return NULL;
-    }
-
-    jint jasset = env->CallIntMethod(jstream, gGetAssetIntMethodID);
-    android::Asset* a = reinterpret_cast<android::Asset*>(jasset);
-    if (NULL == a) {
-        jniThrowNullPointerException(env, "NULL native asset");
-        return NULL;
-    }
-    return new android::AssetStreamAdaptor(a);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static jmethodID    gOutputStream_writeMethodID;
@@ -382,13 +237,6 @@
     return clazz;
 }
 
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
-                                const char fieldname[], const char type[]) {
-    jfieldID id = env->GetFieldID(clazz, fieldname, type);
-    SkASSERT(!env->ExceptionCheck());
-    return id;
-}
-
 static jmethodID getMethodIDCheck(JNIEnv* env, jclass clazz,
                                   const char methodname[], const char type[]) {
     jmethodID id = env->GetMethodID(clazz, methodname, type);
@@ -398,25 +246,9 @@
 
 int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env) {
     jclass inputStream_Clazz = findClassCheck(env, "java/io/InputStream");
-    gInputStream_resetMethodID = getMethodIDCheck(env, inputStream_Clazz, "reset", "()V");
-    gInputStream_markMethodID = getMethodIDCheck(env, inputStream_Clazz, "mark", "(I)V");
-    gInputStream_markSupportedMethodID = getMethodIDCheck(env, inputStream_Clazz, "markSupported", "()Z");
     gInputStream_readMethodID = getMethodIDCheck(env, inputStream_Clazz, "read", "([BII)I");
     gInputStream_skipMethodID = getMethodIDCheck(env, inputStream_Clazz, "skip", "(J)J");
 
-    gByteArrayInputStream_Clazz = findClassCheck(env, "java/io/ByteArrayInputStream");
-    // Ref gByteArrayInputStream_Clazz so we can continue to refer to it when
-    // calling IsInstance.
-    gByteArrayInputStream_Clazz = (jclass) env->NewGlobalRef(gByteArrayInputStream_Clazz);
-    gCountField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "count", "I");
-    gPosField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "pos", "I");
-
-    gAssetInputStream_Clazz = findClassCheck(env, "android/content/res/AssetManager$AssetInputStream");
-    // Ref gAssetInputStream_Clazz so we can continue to refer to it when
-    // calling IsInstance.
-    gAssetInputStream_Clazz = (jclass) env->NewGlobalRef(gAssetInputStream_Clazz);
-    gGetAssetIntMethodID = getMethodIDCheck(env, gAssetInputStream_Clazz, "getAssetInt", "()I");
-
     jclass outputStream_Clazz = findClassCheck(env, "java/io/OutputStream");
     gOutputStream_writeMethodID = getMethodIDCheck(env, outputStream_Clazz, "write", "([BII)V");
     gOutputStream_flushMethodID = getMethodIDCheck(env, outputStream_Clazz, "flush", "()V");
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
index fcc0c9a..ecd270f 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
@@ -4,10 +4,6 @@
 //#include <android_runtime/AndroidRuntime.h>
 #include "jni.h"
 
-namespace android {
-    class AssetStreamAdaptor;
-}
-
 class SkMemoryStream;
 class SkStream;
 class SkStreamRewindable;
@@ -15,6 +11,7 @@
 
 /**
  *  Return an adaptor from a Java InputStream to an SkStream.
+ *  Does not support rewind.
  *  @param env JNIEnv object.
  *  @param stream Pointer to Java InputStream.
  *  @param storage Java byte array for retrieving data from the
@@ -28,7 +25,7 @@
                                        jbyteArray storage);
 
 /**
- *  Copy a Java InputStream.
+ *  Copy a Java InputStream. The result will be rewindable.
  *  @param env JNIEnv object.
  *  @param stream Pointer to Java InputStream.
  *  @param storage Java byte array for retrieving data from the
@@ -39,32 +36,6 @@
 SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
                                         jbyteArray storage);
 
-/**
- *  Get a rewindable stream from a Java InputStream.
- *  @param env JNIEnv object.
- *  @param stream Pointer to Java InputStream.
- *  @param storage Java byte array for retrieving data from the
- *      Java InputStream.
- *  @return SkStreamRewindable Either a wrapper around the Java
- *      InputStream, if possible, or a copy which is rewindable.
- *      Since it may be a wrapper, must not be used after the
- *      caller returns, like the result of CreateJavaInputStreamAdaptor.
- */
-SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream,
-                                        jbyteArray storage);
-
-/**
- *  If the Java InputStream is an AssetInputStream, return an adaptor.
- *  This should not be used after the calling function returns, since
- *  the caller may close the asset. Returns NULL if the stream is
- *  not an AssetInputStream.
- *  @param env JNIEnv object.
- *  @param stream Pointer to Java InputStream.
- *  @return AssetStreamAdaptor representing the InputStream, or NULL.
- *      Must not be held onto.
- */
-android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject stream);
-
 SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
                                          jbyteArray storage);
 #endif
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 2eae841..feb2dec 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -1,4 +1,5 @@
 #include "ScopedLocalRef.h"
+#include "SkFrontBufferedStream.h"
 #include "SkMovie.h"
 #include "SkStream.h"
 #include "GraphicsJNI.h"
@@ -81,23 +82,33 @@
     c->drawBitmap(b, sx, sy, p);
 }
 
+static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jint native_asset) {
+    android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
+    if (asset == NULL) return NULL;
+    SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset));
+    SkMovie* moov = SkMovie::DecodeStream(stream.get());
+    return create_jmovie(env, moov);
+}
+
 static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
 
     NPE_CHECK_RETURN_ZERO(env, istream);
 
-    SkStreamRewindable* strm = CheckForAssetStream(env, istream);
-    jbyteArray byteArray = NULL;
-    ScopedLocalRef<jbyteArray> scoper(env, NULL);
-    if (NULL == strm) {
-        byteArray = env->NewByteArray(16*1024);
-        scoper.reset(byteArray);
-        strm = GetRewindableStream(env, istream, byteArray);
-    }
+    jbyteArray byteArray = env->NewByteArray(16*1024);
+    ScopedLocalRef<jbyteArray> scoper(env, byteArray);
+    SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
     if (NULL == strm) {
         return 0;
     }
 
-    SkMovie* moov = SkMovie::DecodeStream(strm);
+    // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+    // trying to determine the stream's format. The only decoder for movies is GIF, which
+    // will only read 6.
+    // FIXME: Get this number from SkImageDecoder
+    SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
+    SkASSERT(bufferedStream.get() != NULL);
+
+    SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
     strm->unref();
     return create_jmovie(env, moov);
 }
@@ -135,7 +146,9 @@
     {   "setTime",  "(I)Z", (void*)movie_setTime  },
     {   "draw",     "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
                             (void*)movie_draw  },
-    { "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
+    { "nativeDecodeAsset", "(I)Landroid/graphics/Movie;",
+                            (void*)movie_decodeAsset },
+    { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
                             (void*)movie_decodeStream },
     { "nativeDestructor","(I)V", (void*)movie_destructor },
     { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 499a930..6898ab0 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 -->
     <!-- ================================== -->
@@ -2100,6 +2107,13 @@
         android:description="@string/permdesc_captureSecureVideoOutput"
         android:protectionLevel="signature|system" />
 
+    <!--@hide Allows an application to know what content is playing and control its playback.
+         <p>Not for use by third-party applications due to privacy of media consumption</p>  -->
+    <permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
+        android:label="@string/permlab_mediaContentControl"
+        android:description="@string/permdesc_mediaContentControl"
+        android:protectionLevel="signature|system" />
+
     <!-- Required to be able to disable the device (very dangerous!).
     <p>Not for use by third-party applications.. -->
     <permission android:name="android.permission.BRICK"
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
index 584ce05..7f79718 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
index ed317f7..951be79 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
index 40bd746..47f7c29 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
index c49bc84..841c964 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
index 958d023..fd2b63a 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
index 3464f3d..4fa62d7 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
index 3464f3d..242cee9 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
index 5dc3673..3ffd433 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
index c0d8a3d..6065eb7 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
index a920132..63ec738 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
index f6a8b45..1d80d5c 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
index 18c527d..9aed106 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
index 478f2e7..c5e4694 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
index b0be28d..0fe4b14 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
index ec3c748..aaced6e 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
index a929e09..185f9f7 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
index 013ca85..5d695d9 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
index 7b0e089..de15a23 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
index 692d705..beda050 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
index 677069a..9206f57 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
index 677069a..bef235b 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
index 6b5fa5a..63204eb 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
index 6b5fa5a..7b79f3f 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..da023d3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..e9afcc9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
index 5654cd6..1a0bf0d 100644
--- a/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
index 5654cd6..e852a45 100644
--- a/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
index e20b02d..1a0bf0d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
index e20b02d..c9e662d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index 0c689ff..4e40eda 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index f3999204..f1b7036 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
index dc20a8d..f06d898 100644
--- a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
index 272a2a1..0638e58 100644
--- a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
index 84560c5..6d2a8a4 100644
--- a/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
index e101d50..bb43a46 100644
--- a/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
index ea54380..88717cc 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
index ea54380..c759ca4 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
index 6278eef..fe5850c 100644
--- a/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
index aadc6f8..b59edc8 100644
--- a/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
index 9389a08..2eaa6e1 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
index 1109c20..83b3315 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
index 3a8cebc..2b8541c 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
index e9f5f06..e51e72a 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
index eb7a1fd..1940216 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
index 7e4eb5e..c10b235 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
index 7e4eb5e..db9eab0 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
index 194f58e..45252b1 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
index 2a7d0d5..1090816 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
index dff7c00..a740800 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
index 70c705f..faa95fc 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
index 5985e3c..bc82b1a 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
index 2085290..ab3a79b 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
index 4b62750..9b169d4 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
index 000a9c4..29ebf09 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
index 4bc4a30..a703645 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
index dd14aec..42876ce 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
index 2f1f004..c8ffef4 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
index 4bea36b..8be8533 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
index 045dc9a..5e55f6b 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
index 045dc9a..791eda5 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
index 6c4aa16..646ed1c 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
index 6c4aa16..08ea670 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..d120ab1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..3226ab7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
index 6e77525..5f97f2b 100644
--- a/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
index 6e77525..b6427cc 100644
--- a/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
index 13cb131..5f97f2b 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
index 13cb131..779d10e 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index eee058f..a70615a 100644
--- a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index 1ac24be..e7dd785 100644
--- a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
index 2fa15e7..561ac55 100644
--- a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
index a964b22..05ffe3f 100644
--- a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
index b82d1ac..363531a 100644
--- a/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
index f9b5f64..d62c04b 100644
--- a/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
index 670dc2e..92ba340 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
index 670dc2e..e099458 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
index 155c4fc..cdb7b19 100644
--- a/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
index b1223fe..b27c88d 100644
--- a/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.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/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
index c85f135..ebb439d5 100644
--- a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
index 50461d2..c497bf1 100644
--- a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
index ce4b578..30b884e 100644
--- a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
index 8f03489..511f125 100644
--- a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
index a0d64a3..0544d32 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
index 930b5f2..8a751c3 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
index 930b5f2..4294246 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
index 60aede8..bda54ee 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
index 614d27a..812e1b5 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
index f402bd1..6a0ee8d 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
index 041e5cc..4bedd5c 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
index 0804faf..e711d9d 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
index c649599..4bdf427 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
index 149f90d..79567ad 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
index 4145493..65d472f 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
index 85253f7..614f428 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
index efd26b0..f80f9b3 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
index e2305cb..840967c 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
index 6643deb..d7f7ee4 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
index 9d16f32..a1b4e40 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
index 9d16f32..ba9f6a0 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
index fde3ac3..4afca86 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
index fde3ac3..eb79128 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..4baaed3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..5532e88
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
index e4b3393..e9e7c18 100644
--- a/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
index e4b3393..5326b45 100644
--- a/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
index ee5eb6f..e9e7c18 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
index ee5eb6f..74e3843 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index 75c5996..16c1e00 100644
--- a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index a2d6ca1..92a298b 100644
--- a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
index a3c7711..fe701d8 100644
--- a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
index 2a21210..efec27b 100644
--- a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
index aecf6bd..eb44f17 100644
--- a/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
index 3273a22..dfceeed 100644
--- a/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
index 4acb32b..64a2e52 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
index 4acb32b..5110439 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
index e862cb1..1df4a4d 100644
--- a/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
index f1eb673..574dbef 100644
--- a/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
index a54cfbf3..5ba273a 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
index 5afea71..32942b9 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
index f4f58b7..70ee78f 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
index c270562..5bd562e 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
index e3d3eb1..e05017c 100644
--- a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
index 19706e0..a476b99 100644
--- a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
index af8eebb..cfa776c 100644
--- a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
index 9bc460f..181f0a5 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
index 96c63b1..536c618 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
index de76d562b..3bb4ed0 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
index d7eee84..1171dcb 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
index 899e577..03c26f0 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
index aaa6826..f601b3b 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
index e15fc63..dc5233b 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
index cc82a54..2afb586 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
index b756e79..d7416c0 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
index 89bf5b4..47587d2 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
index 50e4940..b258503 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
index 0b77905..703e502 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
index 2e21a6f..966511e 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
index 1a346c9..b6cd6a28 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
index d0c2151..33eb011 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
index fab8dc1..8d55f44 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..c6079cd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..230d649
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
index 7bfdd34..2d4f230 100644
--- a/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
index 13f76de..bd707b0 100644
--- a/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
index a1b5ed2..922cff7 100644
--- a/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
index 7cfb33d..0f58325 100644
--- a/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index 8a67108..432436f 100644
--- a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index f84557f..b18aed6 100644
--- a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
index 103a2c3..5cb3d60 100644
--- a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
index 4e76add..91528b4 100644
--- a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
index d8b02e0..37e1cdc 100644
--- a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
index 807f2c1..2990407 100644
--- a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
index bdcfc74..94ab960 100644
--- a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
index 302b4e2..b795052 100644
--- a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
index 8987d99..c2ee05f 100644
--- a/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
index 92419c4..7faf667 100644
--- a/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_cab_done_holo_dark.xml b/core/res/res/drawable/btn_cab_done_holo_dark.xml
index 14f5777..f865ddd 100644
--- a/core/res/res/drawable/btn_cab_done_holo_dark.xml
+++ b/core/res/res/drawable/btn_cab_done_holo_dark.xml
@@ -17,7 +17,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
           android:autoMirrored="true">
     <item android:state_pressed="true"
-        android:drawable="@drawable/btn_cab_done_pressed_holo_dark" />
+        android:drawable="@drawable/list_pressed_holo_dark" />
     <item android:state_focused="true" android:state_enabled="true"
         android:drawable="@drawable/btn_cab_done_focused_holo_dark" />
     <item android:state_enabled="true"
diff --git a/core/res/res/drawable/btn_cab_done_holo_light.xml b/core/res/res/drawable/btn_cab_done_holo_light.xml
index a9a634f..6d85fc4 100644
--- a/core/res/res/drawable/btn_cab_done_holo_light.xml
+++ b/core/res/res/drawable/btn_cab_done_holo_light.xml
@@ -17,7 +17,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
           android:autoMirrored="true">
     <item android:state_pressed="true"
-        android:drawable="@drawable/btn_cab_done_pressed_holo_light" />
+        android:drawable="@drawable/list_pressed_holo_light" />
     <item android:state_focused="true" android:state_enabled="true"
         android:drawable="@drawable/btn_cab_done_focused_holo_light" />
     <item android:state_enabled="true"
diff --git a/core/res/res/drawable/list_selector_background_transition_holo_dark.xml b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
index 7c68426..288c778 100644
--- a/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
+++ b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
@@ -16,5 +16,5 @@
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@android:drawable/list_pressed_holo_dark"  />
-    <item android:drawable="@android:drawable/list_longpressed_holo"  />
+    <item android:drawable="@android:drawable/list_longpressed_holo_dark"  />
 </transition>
diff --git a/core/res/res/drawable/list_selector_background_transition_holo_light.xml b/core/res/res/drawable/list_selector_background_transition_holo_light.xml
index fc08a84..b729e1f 100644
--- a/core/res/res/drawable/list_selector_background_transition_holo_light.xml
+++ b/core/res/res/drawable/list_selector_background_transition_holo_light.xml
@@ -16,5 +16,5 @@
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@android:drawable/list_pressed_holo_light"  />
-    <item android:drawable="@android:drawable/list_longpressed_holo"  />
+    <item android:drawable="@android:drawable/list_longpressed_holo_light"  />
 </transition>
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 839f3e3..49b2bdc 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 6c8c0c6..32123fb 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -481,10 +481,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"መተግበሪያው በዝቅተኛ ደረጃ ላይ ያሉ የWifi ማሳያዎችን እንዲቆጣጠር ይፈቅድለታል።"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"የድምጽ ውጽዓት ይቅረጹ"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"መተግበሪያው የድምጽ ውጽዓት እንዲቀርጽ እና አቅጣጫውን እንዲያዞር ያስችለዋል።"</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bd394d1..7f3e678 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index f492ff5..040d274 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -481,10 +481,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Разрешава на приложението да контролира функциите от ниско ниво на дисплеите през WiFi."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"записване на възпроизвеждания звук"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Разрешава на приложението да записва и пренасочва възпроизвеждания звук."</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 6ea3299..a58f5b2 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 9822263..3a9da60 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index cbea74f..8853b37 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ca628bf..d0cd8da 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a449835..d5ed353 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index a449835..d5ed353 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 29a3023..9222e70 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 96d81d4..6191dc1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index fd1da20..8e93ec1 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 120f3ee..74c904f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 98faa98..9c05971 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 27ef5d7..563ed73 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index e7e6518..8c18c58 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +479,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"एप्स को Wifi डिस्प्ले की निम्न-स्तर की सुविधाएं नियंत्रित करने देता है."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ऑडियो आउटपुट को कैप्‍चर करें"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"एप्‍स को ऑडियो आउटपुट को कैप्‍चर और रीडायरेक्‍ट करने देता है."</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e839579..e9f5ed1 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b313efb..8343bb3 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index d3b8762..97643c9 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +479,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Թույլ է տալիս հավելվածին կառավարել WiFi ցուցադրիչների ցածր մակարդակի գործառույթները:"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"պահել աուդիո արտածումը"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Թույլ է տալիս ծրագրին պահել և վերահղել աուդիո արտածումը:"</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 078fb0c..6de81ac 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 613715b..5ae7c5f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f01dd94..b9eecd0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 3ad4d5a..c2401bc 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 56d18d3..e4e5f92 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -481,10 +481,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"აპს შეეძლება აკონტროლოს Wifi ეკრანების დაბალი დონის ფუნქციები."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"გამომავალი აუდიოს დაჭერა"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"საშუალებას აძლევს აპს დაიჭიროს და გადაამისამართოს გამომავალი აუდიო."</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 4c131f5..f56d261 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +479,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ឲ្យ​កម្មវិធី​ពិនិត្យ​លក្ខណៈ​កម្រិត​ទាប​​នៃ​ការ​បង្ហាញ​វ៉ាយហ្វាយ។"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ចាប់​យក​លទ្ធផល​អូឌីយ៉ូ"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"​ឱ្យ​កម្មវិធី​ដើម្បី​ចាប់​យក​ និង​​ប្ដូរ​​ទិស​លទ្ធផល​អូឌីយ៉ូ​។"</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 21e343f..41e66ce 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
@@ -685,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 e8cd4e2..9d088f6 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +479,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"ອະນຸຍາດໃຫ້ແອັບຯ ຄວບຄຸມຄວາມສາມາດລະດັບຕໍ່າຂອງການສະແດງຜົນ Wifi."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"ບັນທຶກສຽງອອກ"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ອະນຸຍາດໃຫ້ແອັບຯບັນທຶກ ແລະປ່ຽນເສັ້ນທາງການປ້ອນຂໍ້ມູນອອກຂອງສຽງ."</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index ff2079a..c575a21 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 55dece8..0dda696 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index e50854d..b456d3e 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +479,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"Апп нь Wifi дэлгэцний доод-төвшиний функцийг удирдах боломжтой."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"аудио гаралтыг барих"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Апп-т аудио гаралтыг барих, дахин чиглүүлэхийг зөвшөөрнө."</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 1fed75d..b266591 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 625fb38..c0d58aa 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index bd45ddc..3a97f95 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -441,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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 8c7f072..3196373 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 4b6c7fa..3a86f55 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 75b0924..9842414 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index f710219..e96a40d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 500ced4..d944031 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 1374366..b047c1a9 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index f119865..7480afd 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 40405ae..2c04831 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 851e6b6..2049364 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -452,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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
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 a19ddaa..a0b0255 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +479,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"อนุญาตให้แอปควบคุมคุณลักษณะต่างๆ ในระดับล่างของการแสดงผลด้วย WiFi"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"บันทึกเอาต์พุตเสียง"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"อนุญาตให้แอปบันทึกและเปลี่ยนเส้นทางเอาต์พุตเสียง"</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index c357eb4..5b06737 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 22a3eef..14f98d7 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6a9677f..3ff9fd9 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 954e52d..26e3f6e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index c765417..b250f14 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -481,10 +481,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允许应用控制 WLAN 显示设备的基础功能。"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"捕获音频输出"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允许该应用捕获和重定向音频输出。"</string>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
@@ -652,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>
@@ -695,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>
@@ -703,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>
@@ -761,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>
@@ -1182,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>
@@ -1435,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 3b03aa5..e924d01 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index b26b989..7be248f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -132,10 +132,8 @@
     <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="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>
@@ -481,10 +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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +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>
-    <!-- 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_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>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 24006fd..f96b062 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -132,10 +132,8 @@
     <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>
-    <!-- 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="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>
@@ -481,10 +479,8 @@
     <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>
-    <!-- no translation found for permlab_captureAudioHotword (1890553935650349808) -->
-    <skip />
-    <!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
-    <skip />
+    <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>
@@ -552,12 +548,9 @@
     <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 uhlelo lokusebenza ukuthi inqande ucingo ukuthi lulale."</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_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>
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 a03378e..56b8ca4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1433,6 +1433,11 @@
     <string name="permdesc_captureSecureVideoOutput">Allows the app to capture and redirect secure video output.</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_mediaContentControl">control media playback and metadata access</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_mediaContentControl">Allows the app to control media playback and access the media information (title, author...).</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_modifyAudioSettings">change your audio settings</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_modifyAudioSettings">Allows the app to modify global audio settings such as volume and which speaker is used for output.</string>
@@ -1898,6 +1903,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>
@@ -4296,19 +4306,111 @@
     <!-- ISO (European standard) C10 media (paper) size: 1.10" x 1.57" -->
     <string name="mediaSize_iso_c10">ISO C10</string>
 
-    <!-- North America Letter media (paper) size: 8.5" × 11" -->
+    <!-- North America Letter media (paper) size: 8.5" × 11" (279mm x 216mm) -->
     <string name="mediaSize_na_letter">Letter</string>
-    <!-- North America Government Letter media (paper) size: 8.0" × 10.5" -->
+    <!-- North America Government Letter media (paper) size: 8.0" × 10.5" (203mm x 267mm) -->
     <string name="mediaSize_na_gvrnmt_letter">Government Letter</string>
-    <!-- North America Legal media (paper) size: 8.5" × 14" -->
+    <!-- North America Legal media (paper) size: 8.5" × 14" (216mm x 356mm) -->
     <string name="mediaSize_na_legal">Legal</string>
-    <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" -->
+    <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" (203mm × 127mm) -->
     <string name="mediaSize_na_junior_legal">Junior Legal</string>
-    <!-- North America Ledger media (paper) size: 17" × 11" -->
+    <!-- North America Ledger media (paper) size: 17" × 11" (432mm × 279mm) -->
     <string name="mediaSize_na_ledger">Ledger</string>
-    <!-- North America Tabloid media (paper) size: 11" × 17" -->
+    <!-- North America Tabloid media (paper) size: 11" × 17" (279mm × 432mm) -->
     <string name="mediaSize_na_tabloid">Tabloid</string>
 
+    <!-- North America Index Card 3x5 media (paper) size: 3" x 5" (76mm x 127mm) -->
+    <string name="mediaSize_na_index_3x5">Index Card 3x5</string>
+    <!-- North America Index Card 4x6 media (paper) size: 4" x 6" (102mm x 152mm) -->
+    <string name="mediaSize_na_index_4x6">Index Card 4x6</string>
+    <!-- North America Index Card 5x8 media (paper) size: 5" x 8" (127mm x 203mm) -->
+    <string name="mediaSize_na_index_5x8">Index Card 5x8</string>
+    <!-- North America Monarch media (paper) size: 7.25" x 10.5" (184mm x 267mm) -->
+    <string name="mediaSize_na_monarch">Monarch</string>
+    <!-- North America Quarto media (paper) size: 8" x 10" (203mm x 254mm) -->
+    <string name="mediaSize_na_quarto">Quarto</string>
+    <!-- North America Foolscap media (paper) size: 8" x 13" (203mm x 330mm) -->
+    <string name="mediaSize_na_foolscap">Foolscap</string>
+
+    <!-- Chinese Roc 8k media (paper) size: 270mm x 390mm (10.629" x 15.3543") -->
+    <string name="mediaSize_chinese_roc_8k">ROC 8K</string>
+    <!-- Chinese Roc 16k media (paper) size: 195mm x 270mm (7.677" x 10.629") -->
+    <string name="mediaSize_chinese_roc_16k">ROC 16K</string>
+
+    <!-- Chinese PRC 1 media (paper) size: 102mm x 165mm (4.015" x 6.496") -->
+    <string name="mediaSize_chinese_prc_1">PRC 1</string>
+    <!-- Chinese PRC 2 media (paper) size: 102mm x 176mm (4.015" x 6.929") -->
+    <string name="mediaSize_chinese_prc_2">PRC 2</string>
+    <!-- Chinese PRC 3 media (paper) size: 125mm x 176mm (4.921" x 6.929") -->
+    <string name="mediaSize_chinese_prc_3">PRC 3</string>
+    <!-- Chinese PRC 4 media (paper) size: 110mm x 208mm (4.330" x 8.189") -->
+    <string name="mediaSize_chinese_prc_4">PRC 4</string>
+    <!-- Chinese PRC 5 media (paper) size: 110mm x 220mm (4.330" x 8.661") -->
+    <string name="mediaSize_chinese_prc_5">PRC 5</string>
+    <!-- Chinese PRC 6 media (paper) size: 120mm x 320mm (4.724" x 12.599") -->
+    <string name="mediaSize_chinese_prc_6">PRC 6</string>
+    <!-- Chinese PRC 7 media (paper) size: 160mm x 230mm (6.299" x 9.055") -->
+    <string name="mediaSize_chinese_prc_7">PRC 7</string>
+    <!-- Chinese PRC 8 media (paper) size: 120mm x 309mm (4.724" x 12.165") -->
+    <string name="mediaSize_chinese_prc_8">PRC 8</string>
+    <!-- Chinese PRC 9 media (paper) size: 229mm x 324mm (9.016" x 12.756") -->
+    <string name="mediaSize_chinese_prc_9">PRC 9</string>
+    <!-- Chinese PRC 10 media (paper) size: 324mm x 458mm (12.756" x 18.032") -->
+    <string name="mediaSize_chinese_prc_10">PRC 10</string>
+
+    <!-- Chinese RPC 16K media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+    <string name="mediaSize_chinese_prc_16k">PRC 16K</string>
+    <!-- Chinese Pa Kai media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+    <string name="mediaSize_chinese_om_pa_kai">Pa Kai</string>
+    <!-- Chinese Dai Pa Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+    <string name="mediaSize_chinese_om_dai_pa_kai">Dai Pa Kai</string>
+    <!-- Chinese Jurro Ku Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+    <string name="mediaSize_chinese_om_jurro_ku_kai">Jurro Ku Kai</string>
+
+    <!-- Japanese JIS B10 media (paper) size: 32mm x 45mm (1.259" x 1.772") -->
+    <string name="mediaSize_japanese_jis_b10">JIS B10</string>
+    <!-- Japanese JIS B9 media (paper) size: 45mm x 64mm (1.772" x 2.52") -->
+    <string name="mediaSize_japanese_jis_b9">JIS B9</string>
+    <!-- Japanese JIS B8 media (paper) size: 64mm x 91mm (2.52" x 3.583") -->
+    <string name="mediaSize_japanese_jis_b8">JIS B8</string>
+    <!-- Japanese JIS B7 media (paper) size: 91mm x 128mm (3.583" x 5.049") -->
+    <string name="mediaSize_japanese_jis_b7">JIS B7</string>
+    <!-- Japanese JIS B6 media (paper) size: 128mm x 182mm (5.049" x 7.165") -->
+    <string name="mediaSize_japanese_jis_b6">JIS B6</string>
+    <!-- Japanese JIS B5 media (paper) size: 182mm x 257mm (7.165" x 10.118") -->
+    <string name="mediaSize_japanese_jis_b5">JIS B5</string>
+    <!-- Japanese JIS B4 media (paper) size: 257mm x 364mm (10.118" x 14.331") -->
+    <string name="mediaSize_japanese_jis_b4">JIS B4</string>
+    <!-- Japanese JIS B3 media (paper) size: 364mm x 515mm (14.331" x 20.276") -->
+    <string name="mediaSize_japanese_jis_b3">JIS B3</string>
+    <!-- Japanese JIS B2 media (paper) size: 515mm x 728mm (20.276" x 28.661") -->
+    <string name="mediaSize_japanese_jis_b2">JIS B2</string>
+    <!-- Japanese JIS B1 media (paper) size: 728mm x 1030mm (28.661" x 40.551") -->
+    <string name="mediaSize_japanese_jis_b1">JIS B1</string>
+    <!-- Japanese JIS B0 media (paper) size: 1030mm x 1456mm (40.551" x 57.323") -->
+    <string name="mediaSize_japanese_jis_b0">JIS B0</string>
+
+    <!-- Japanese JIS Exec media (paper) size: 216mm x 330mm (8.504" x 12.992") -->
+    <string name="mediaSize_japanese_jis_exec">JIS Exec</string>
+
+    <!-- Japanese Chou4 media (paper) size: 90mm x 205mm (3.543" x 8.071") -->
+    <string name="mediaSize_japanese_chou4">Chou4</string>
+    <!-- Japanese Chou3 media (paper) size: 120mm x 235mm (4.724" x 9.252") -->
+    <string name="mediaSize_japanese_chou3">Chou3</string>
+    <!-- Japanese Chou2 media (paper) size: 111.1mm x 146mm (4.374" x 5.748") -->
+    <string name="mediaSize_japanese_chou2">Chou2</string>
+
+    <!-- Japanese Hagaki media (paper) size: 100mm x 148mm (3.937" x 5.827") -->
+    <string name="mediaSize_japanese_hagaki">Hagaki </string>
+    <!-- Japanese Oufuku media (paper) size: 148mm x 200mm (5.827" x 7.874") -->
+    <string name="mediaSize_japanese_oufuku">Oufuku </string>
+    <!-- Japanese Kahu media (paper) size: 240mm x 322.1mm (9.449" x 12.681") -->
+    <string name="mediaSize_japanese_kahu">Kahu</string>
+    <!-- Japanese Kaku2 media (paper) size: 240mm x 332mm (9.449" x 13.071") -->
+    <string name="mediaSize_japanese_kaku2">Kaku2</string>
+    <!-- Japanese You4 media (paper) size: 105mm x 235mm (4.134" x 9.252") -->
+    <string name="mediaSize_japanese_you4">You4</string>
+
     <!-- Write fail reason: printing was cancelled.[CHAR LIMIT=none] -->
     <string name="write_fail_reason_cancelled">Cancelled</string>
     <!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] -->
@@ -4344,9 +4446,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 4148f20..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" />
@@ -877,6 +878,48 @@
   <java-symbol type="string" name="mediaSize_na_junior_legal" />
   <java-symbol type="string" name="mediaSize_na_ledger" />
   <java-symbol type="string" name="mediaSize_na_tabloid" />
+  <java-symbol type="string" name="mediaSize_na_index_3x5" />
+  <java-symbol type="string" name="mediaSize_na_index_4x6" />
+  <java-symbol type="string" name="mediaSize_na_index_5x8" />
+  <java-symbol type="string" name="mediaSize_na_monarch" />
+  <java-symbol type="string" name="mediaSize_na_quarto" />
+  <java-symbol type="string" name="mediaSize_na_foolscap" />
+  <java-symbol type="string" name="mediaSize_chinese_roc_8k" />
+  <java-symbol type="string" name="mediaSize_chinese_roc_16k" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_1" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_2" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_3" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_4" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_5" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_6" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_7" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_8" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_9" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_10" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_16k" />
+  <java-symbol type="string" name="mediaSize_chinese_om_pa_kai" />
+  <java-symbol type="string" name="mediaSize_chinese_om_dai_pa_kai" />
+  <java-symbol type="string" name="mediaSize_chinese_om_jurro_ku_kai" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b10" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b9" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b8" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b7" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b6" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b5" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b4" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b3" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b2" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b1" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b0" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_exec" />
+  <java-symbol type="string" name="mediaSize_japanese_chou4" />
+  <java-symbol type="string" name="mediaSize_japanese_chou3" />
+  <java-symbol type="string" name="mediaSize_japanese_chou2" />
+  <java-symbol type="string" name="mediaSize_japanese_hagaki" />
+  <java-symbol type="string" name="mediaSize_japanese_oufuku" />
+  <java-symbol type="string" name="mediaSize_japanese_kahu" />
+  <java-symbol type="string" name="mediaSize_japanese_kaku2" />
+  <java-symbol type="string" name="mediaSize_japanese_you4" />
   <java-symbol type="string" name="reason_unknown" />
   <java-symbol type="string" name="restr_pin_enter_admin_pin" />
   <java-symbol type="string" name="restr_pin_enter_pin" />
@@ -885,7 +928,6 @@
   <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" />
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/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 23606a1..c8ace44 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -569,10 +569,7 @@
                 final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
                 bm = nativeDecodeAsset(asset, outPadding, opts);
             } else {
-                byte [] tempStorage = null;
-                if (opts != null) tempStorage = opts.inTempStorage;
-                if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
-                bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
+                bm = decodeStreamInternal(is, outPadding, opts);
             }
 
             if (bm == null && opts != null && opts.inBitmap != null) {
@@ -588,6 +585,18 @@
     }
 
     /**
+     * Private helper function for decoding an InputStream natively. Buffers the input enough to
+     * do a rewind as needed, and supplies temporary storage if necessary. is MUST NOT be null.
+     */
+    private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
+        // ASSERT(is != null);
+        byte [] tempStorage = null;
+        if (opts != null) tempStorage = opts.inTempStorage;
+        if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
+        return nativeDecodeStream(is, tempStorage, outPadding, opts);
+    }
+
+    /**
      * Decode an input stream into a bitmap. If the input stream is null, or
      * cannot be used to decode a bitmap, the function returns null.
      * The stream's position will be where ever it was after the encoded data
@@ -624,13 +633,8 @@
                 bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
             } else {
                 FileInputStream fis = new FileInputStream(fd);
-                // FIXME: If nativeDecodeStream grabbed the pointer to tempStorage
-                // from Options, this code would not need to be duplicated.
-                byte [] tempStorage = null;
-                if (opts != null) tempStorage = opts.inTempStorage;
-                if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
                 try {
-                    bm = nativeDecodeStream(fis, tempStorage, outPadding, opts);
+                    bm = decodeStreamInternal(fis, outPadding, opts);
                 } finally {
                     try {
                         fis.close();
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 4a33453..9419faf 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -16,12 +16,13 @@
 
 package android.graphics;
 
+import android.content.res.AssetManager;
 import java.io.InputStream;
 import java.io.FileInputStream;
 
 public class Movie {
     private final int mNativeMovie;
-    
+
     private Movie(int nativeMovie) {
         if (nativeMovie == 0) {
             throw new RuntimeException("native movie creation failed");
@@ -42,7 +43,20 @@
         draw(canvas, x, y, null);
     }
 
-    public static native Movie decodeStream(InputStream is);
+    public static Movie decodeStream(InputStream is) {
+        if (is == null) {
+            return null;
+        }
+        if (is instanceof AssetManager.AssetInputStream) {
+            final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+            return nativeDecodeAsset(asset);
+        }
+
+        return nativeDecodeStream(is);
+    }
+
+    private static native Movie nativeDecodeAsset(int asset);
+    private static native Movie nativeDecodeStream(InputStream is);
     public static native Movie decodeByteArray(byte[] data, int offset,
                                                int length);
 
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index c0b77c7..7eb7028 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -275,6 +275,11 @@
         DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
         buffer.writeCommand(0, "multiDraw");
         buffer.writeCommand(1, op->name());
+
+#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
+        renderer.eventMark("multiDraw");
+        renderer.eventMark(op->name());
+#endif
         status_t status = op->multiDraw(renderer, dirty, mOps, mBounds);
 
 #if DEBUG_MERGE_BEHAVIOR
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index a17942e..b052461 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -813,12 +813,15 @@
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
             const DeferredDisplayState& state) {
         deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
-        deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
+        deferInfo.mergeId = getAtlasEntry() ?
+                (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
 
+        // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
         // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
         // MergingDrawBatch::canMergeWith()
         // TODO: support clipped bitmaps by handling them in SET_TEXTURE
-        deferInfo.mergeable = state.mMatrix.isSimple() && !state.mClipSideFlags &&
+        deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
+                !state.mClipSideFlags &&
                 OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
                 (mBitmap->getConfig() != SkBitmap::kA8_Config);
     }
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 65e7eae..1948778 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -110,6 +110,10 @@
                 mType |= kTypeRectToRect;
             }
         }
+
+        if (m00 > 0.0f && m11 > 0.0f) {
+            mType |= kTypePositiveScale;
+        }
     }
     return mType;
 }
@@ -122,6 +126,10 @@
     return getType() & kTypeRectToRect;
 }
 
+bool Matrix4::positiveScale() const {
+    return getType() & kTypePositiveScale;
+}
+
 bool Matrix4::changesBounds() const {
     return getType() & (kTypeScale | kTypeAffine | kTypePerspective);
 }
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 5116203..e2c5b20 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -64,7 +64,8 @@
         kTypeAffine = 0x4,
         kTypePerspective = 0x8,
         kTypeRectToRect = 0x10,
-        kTypeUnknown = 0x20,
+        kTypePositiveScale = 0x20,
+        kTypeUnknown = 0x40,
     };
 
     static const int sGeometryMask = 0xf;
@@ -183,6 +184,7 @@
     bool isIdentity() const;
     bool isPerspective() const;
     bool rectToRect() const;
+    bool positiveScale() const;
 
     bool changesBounds() const;
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2066f69..89a82fd 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1628,14 +1628,7 @@
 
     Rect r(left, top, right, bottom);
     currentTransform().mapRect(r);
-
-    if (snapOut) {
-        // snapOut is generally used to account for 1 pixel ramp (in window coordinates)
-        // outside of the provided rect boundaries in tessellated AA geometry
-        r.snapOutToPixelBoundaries();
-    } else {
-        r.snapToPixelBoundaries();
-    }
+    r.snapGeometryToPixelBoundaries(snapOut);
 
     Rect clipRect(*mSnapshot->clipRect);
     clipRect.snapToPixelBoundaries();
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 9e4670e..7814a01 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -20,6 +20,7 @@
 #include <utils/Trace.h>
 
 #include "Program.h"
+#include "Vertex.h"
 
 namespace android {
 namespace uirenderer {
@@ -172,7 +173,7 @@
             // up and to the left.
             // This offset value is based on an assumption that some hardware may use as
             // little as 12.4 precision, so we offset by slightly more than 1/16.
-            p.translate(.065, .065);
+            p.translate(Vertex::gGeometryFudgeFactor, Vertex::gGeometryFudgeFactor);
             glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]);
         }
         mProjection = projectionMatrix;
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 7605307..dabd8d4 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -21,6 +21,8 @@
 
 #include <utils/Log.h>
 
+#include "Vertex.h"
+
 namespace android {
 namespace uirenderer {
 
@@ -171,17 +173,37 @@
     }
 
     /**
-     * Similar to snapToPixelBoundaries, but used for AA geometry with a ramp perimeter.
+     * Similar to snapToPixelBoundaries, but estimates bounds conservatively to handle GL rounding
+     * errors.
      *
-     * We inset the data by a fudge factor of slightly over 1/16 (similar to when drawing non-AA
-     * lines) before rounding out so that insignificant amounts of ramp geometry (esp. from rounding
-     * errors) are ignored.
+     * This function should be used whenever estimating the damage rect of geometry already mapped
+     * into layer space.
      */
-    void snapOutToPixelBoundaries() {
-        left = floorf(left + 0.065f);
-        top = floorf(top + 0.065f);
-        right = ceilf(right - 0.065f);
-        bottom = ceilf(bottom - 0.065f);
+    void snapGeometryToPixelBoundaries(bool snapOut) {
+        if (snapOut) {
+            /* For AA geometry with a ramp perimeter, don't snap by rounding - AA geometry will have
+             * a 0.5 pixel perimeter not accounted for in its bounds. Instead, snap by
+             * conservatively rounding out the bounds with floor/ceil.
+             *
+             * In order to avoid changing integer bounds with floor/ceil due to rounding errors
+             * inset the bounds first by the fudge factor. Very small fraction-of-a-pixel errors
+             * from this inset will only incur similarly small errors in output, due to transparency
+             * in extreme outside of the geometry.
+             */
+            left = floorf(left + Vertex::gGeometryFudgeFactor);
+            top = floorf(top + Vertex::gGeometryFudgeFactor);
+            right = ceilf(right - Vertex::gGeometryFudgeFactor);
+            bottom = ceilf(bottom - Vertex::gGeometryFudgeFactor);
+        } else {
+            /* For other geometry, we do the regular rounding in order to snap, but also outset the
+             * bounds by a fudge factor. This ensures that ambiguous geometry (e.g. a non-AA Rect
+             * with top left at (0.5, 0.5)) will err on the side of a larger damage rect.
+             */
+            left = floorf(left + 0.5f - Vertex::gGeometryFudgeFactor);
+            top = floorf(top + 0.5f - Vertex::gGeometryFudgeFactor);
+            right = floorf(right + 0.5f + Vertex::gGeometryFudgeFactor);
+            bottom = floorf(bottom + 0.5f + Vertex::gGeometryFudgeFactor);
+        }
     }
 
     void snapToPixelBoundaries() {
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index c06762f..790d4fc 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -26,6 +26,15 @@
  * Simple structure to describe a vertex with a position and a texture.
  */
 struct Vertex {
+    /**
+     * Fudge-factor used to disambiguate geometry pixel positioning.
+     *
+     * Used to offset lines and points to avoid ambiguous intersection with pixel centers (see
+     * Program::set()), and used to make geometry damage rect calculation conservative (see
+     * Rect::snapGeometryToPixelBoundaries())
+     */
+    static const float gGeometryFudgeFactor = 0.0656f;
+
     float position[2];
 
     static inline void set(Vertex* vertex, float x, float y) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 845baaf..a4009cf 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -323,6 +323,12 @@
     public static final int FLAG_FIXED_VOLUME = 1 << 5;
 
     /**
+     * Indicates the volume set/adjust call is for Bluetooth absolute volume
+     * @hide
+     */
+    public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
+
+    /**
      * Ringer mode that will be silent and will not vibrate. (This overrides the
      * vibrate setting.)
      *
@@ -438,6 +444,19 @@
 
     /**
      * @hide
+     * @param KeyEvent
+     */
+    protected void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+        IAudioService service = getService();
+        try {
+            service.dispatchMediaKeyEvent(keyEvent);
+        } catch (RemoteException e) {
+            Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+        }
+    }
+
+    /**
+     * @hide
      */
     public void preDispatchKeyEvent(KeyEvent event, int stream) {
         /*
@@ -2229,6 +2248,49 @@
 
     /**
      * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param rctlr
+     * @return true if the {@link RemoteController} was successfully registered, false if an
+     *     error occurred, due to an internal system error, or insufficient permissions.
+     */
+    public boolean registerRemoteController(RemoteController rctlr) {
+        if (rctlr == null) {
+            return false;
+        }
+        IAudioService service = getService();
+        try {
+            boolean reg = service.registerRemoteControlDisplay(rctlr.getRcDisplay(),
+                    // passing a negative value for art work width and height
+                    //   as they are still unknown at this stage
+                    /*w*/-1, /*h*/ -1);
+            rctlr.setIsRegistered(reg);
+            return reg;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
+            return false;
+        }
+    }
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param rctlr
+     */
+    public void unregisterRemoteController(RemoteController rctlr) {
+        if (rctlr == null) {
+            return;
+        }
+        IAudioService service = getService();
+        try {
+            service.unregisterRemoteControlDisplay(rctlr.getRcDisplay());
+            rctlr.setIsRegistered(false);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e);
+        }
+    }
+
+    /**
+     * @hide
      * Registers a remote control display that will be sent information by remote control clients.
      * Use this method if your IRemoteControlDisplay is not going to display artwork, otherwise
      * use {@link #registerRemoteControlDisplay(IRemoteControlDisplay, int, int)} to pass the
@@ -2257,8 +2319,6 @@
         }
         IAudioService service = getService();
         try {
-            // passing a negative value for art work width and height as they are unknown at
-            // this stage
             service.registerRemoteControlDisplay(rcd, w, h);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
@@ -2351,13 +2411,15 @@
 
     /**
      * @hide
-     * Notify the user of a RemoteControlClient that it should update its metadata
+     * Notify the user of a RemoteControlClient that it should update its metadata with the
+     * new value for the given key.
      * @param generationId the RemoteControlClient generation counter for which this request is
      *         issued. Requests for an older generation than current one will be ignored.
      * @param key the metadata key for which a new value exists
      * @param value the new metadata value
      */
-    public void updateRemoteControlClientMetadata(int generationId, int key, long value) {
+    public void updateRemoteControlClientMetadata(int generationId, int key,
+            Rating value) {
         IAudioService service = getService();
         try {
             service.updateRemoteControlClientMetadata(generationId, key, value);
@@ -2397,20 +2459,6 @@
         }
     }
 
-    /**
-     * @hide
-     * Notifies AudioService of the volume set on the A2DP device as a callback, so AudioService
-     * is able to update the UI.
-     */
-    public void avrcpUpdateVolume(int oldVolume, int volume) {
-        IAudioService service = getService();
-        try {
-            service.avrcpUpdateVolume(oldVolume, volume);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in avrcpUpdateVolume", e);
-        }
-    }
-
      /**
       * {@hide}
       */
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index b72551a..3425c91 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -843,6 +843,13 @@
         boolean adjustVolume = true;
         int step;
 
+        // skip a2dp absolute volume control request when the device
+        // is not an a2dp device
+        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+            return;
+        }
+
         if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
             return;
@@ -892,15 +899,18 @@
         int oldIndex = mStreamStates[streamType].getIndex(device);
 
         if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+
             // Check if volume update should be send to AVRCP
-            synchronized (mA2dpAvrcpLock) {
-                if (mA2dp != null && mAvrcpAbsVolSupported) {
-                    mA2dp.adjustAvrcpAbsoluteVolume(direction);
-                    return;
-                    // No need to send volume update, because we will update the volume with a
-                    // callback from Avrcp.
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+                synchronized (mA2dpAvrcpLock) {
+                    if (mA2dp != null && mAvrcpAbsVolSupported) {
+                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
+                    }
                 }
             }
+
             if ((direction == AudioManager.ADJUST_RAISE) &&
                     !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
                 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
@@ -985,6 +995,13 @@
         final int device = getDeviceForStream(streamType);
         int oldIndex;
 
+        // skip a2dp absolute volume control request when the device
+        // is not an a2dp device
+        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+            return;
+        }
+
         if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
             return;
@@ -998,12 +1015,13 @@
 
             index = rescaleIndex(index * 10, streamType, streamTypeAlias);
 
-            synchronized (mA2dpAvrcpLock) {
-                if (mA2dp != null && mAvrcpAbsVolSupported) {
-                    mA2dp.setAvrcpAbsoluteVolume(index);
-                    return;
-                    // No need to send volume update, because we will update the volume with a
-                    // callback from Avrcp.
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+                synchronized (mA2dpAvrcpLock) {
+                    if (mA2dp != null && mAvrcpAbsVolSupported) {
+                        mA2dp.setAvrcpAbsoluteVolume(index);
+                    }
                 }
             }
 
@@ -2835,7 +2853,12 @@
             int index;
             if (isMuted()) {
                 index = 0;
-            } else {
+            } else if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC &&
+                       (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                       mAvrcpAbsVolSupported) {
+                index = (mIndexMax + 5)/10;
+            }
+            else {
                 index = (getIndex(device) + 5)/10;
             }
             AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
@@ -3650,6 +3673,9 @@
     private void makeA2dpDeviceAvailable(String address) {
         // enable A2DP before notifying A2DP connection to avoid unecessary processing in
         // audio policy manager
+        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
         setBluetoothA2dpOnInt(true);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_AVAILABLE,
@@ -3666,6 +3692,9 @@
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpDeviceUnavailableNow(String address) {
+        synchronized (mA2dpAvrcpLock) {
+            mAvrcpAbsVolSupported = false;
+        }
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_UNAVAILABLE,
                 address);
@@ -3706,19 +3735,6 @@
             address = "";
         }
 
-        // Disable absolute volume, if device is disconnected
-        synchronized (mA2dpAvrcpLock) {
-            if (state == BluetoothProfile.STATE_DISCONNECTED && mAvrcpAbsVolSupported) {
-                mAvrcpAbsVolSupported = false;
-                sendMsg(mAudioHandler,
-                        MSG_SET_DEVICE_VOLUME,
-                        SENDMSG_QUEUE,
-                        getDeviceForStream(AudioSystem.STREAM_MUSIC),
-                        0,
-                        mStreamStates[AudioSystem.STREAM_MUSIC],
-                        0);
-            }
-        }
         synchronized (mConnectedDevices) {
             boolean isConnected =
                 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
@@ -3773,27 +3789,12 @@
         // address is not used for now, but may be used when multiple a2dp devices are supported
         synchronized (mA2dpAvrcpLock) {
             mAvrcpAbsVolSupported = support;
-            if (support) {
-                VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
-                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
-                streamState.setIndex(streamState.getMaxIndex(), device);
-                sendMsg(mAudioHandler,
-                        MSG_SET_DEVICE_VOLUME,
-                        SENDMSG_QUEUE,
-                        device,
-                        0,
-                        streamState,
-                        0);
-            }
+            VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
         }
     }
 
-    public void avrcpUpdateVolume(int oldVolume, int volume) {
-        mStreamStates[AudioSystem.STREAM_MUSIC].
-                        setIndex(volume, getDeviceForStream(AudioSystem.STREAM_MUSIC));
-        sendVolumeUpdate(AudioSystem.STREAM_MUSIC, oldVolume, volume, AudioManager.FLAG_SHOW_UI);
-    }
-
     private boolean handleDeviceConnection(boolean connected, int device, String params) {
         synchronized (mConnectedDevices) {
             boolean isConnected = (mConnectedDevices.containsKey(device) &&
@@ -4142,8 +4143,17 @@
     //==========================================================================================
     // RemoteControlDisplay / RemoteControlClient / Remote info
     //==========================================================================================
-    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
+    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
+        if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.MEDIA_CONTENT_CONTROL)) {
+            mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
+            return true;
+        } else {
+            Log.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
+                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
+                    " to register IRemoteControlDisplay");
+            return false;
+        }
     }
 
     public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
@@ -4189,7 +4199,7 @@
         mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
     }
 
-    public void updateRemoteControlClientMetadata(int generationId, int key, long value) {
+    public void updateRemoteControlClientMetadata(int generationId, int key, Rating value) {
         mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value);
     }
 
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fe060f8..e3b87dd 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -26,6 +26,7 @@
 import android.media.IRemoteControlDisplay;
 import android.media.IRemoteVolumeObserver;
 import android.media.IRingtonePlayer;
+import android.media.Rating;
 import android.net.Uri;
 import android.view.KeyEvent;
 
@@ -100,8 +101,6 @@
 
     oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
 
-    oneway void avrcpUpdateVolume(int oldVolume, int volume);
-
     void setSpeakerphoneOn(boolean on);
 
     boolean isSpeakerphoneOn();
@@ -142,7 +141,7 @@
      * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
      *   display doesn't need to receive artwork.
      */
-    oneway void   registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
+    boolean registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
     /**
      * Unregister an IRemoteControlDisplay.
      * No effect if the IRemoteControlDisplay hasn't been successfully registered.
@@ -180,13 +179,14 @@
      */
      void setRemoteControlClientPlaybackPosition(int generationId, long timeMs);
      /**
-      * Notify the user of a RemoteControlClient that it should update its metadata
+      * Notify the user of a RemoteControlClient that it should update its metadata with the
+      * new value for the given key.
       * @param generationId the RemoteControlClient generation counter for which this request is
       *         issued. Requests for an older generation than current one will be ignored.
       * @param key the metadata key for which a new value exists
       * @param value the new metadata value
       */
-     void updateRemoteControlClientMetadata(int generationId, int key, long value);
+     void updateRemoteControlClientMetadata(int generationId, int key, in Rating value);
 
     /**
      * Do not use directly, use instead
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
index dd729b4..48079f2 100644
--- a/media/java/android/media/IRemoteControlClient.aidl
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -17,6 +17,7 @@
 
 import android.graphics.Bitmap;
 import android.media.IRemoteControlDisplay;
+import android.media.Rating;
 
 /**
  * @hide
@@ -49,5 +50,5 @@
     void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
     void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync);
     void seekTo(int clientGeneration, long timeMs);
-    void updateMetadata(int clientGeneration, int key, long value);
+    void updateMetadata(int clientGeneration, int key, in Rating value);
 }
\ No newline at end of file
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..1bd32c4 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -20,6 +20,7 @@
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
 import android.view.Surface;
 
 import java.lang.ref.WeakReference;
@@ -40,41 +41,68 @@
  * <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. Note that
+     *            not all formats is supported, like ImageFormat.NV21.
+     * @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;
@@ -89,6 +117,11 @@
                 "Maximum outstanding image count must be at least 1");
         }
 
+        if (format == ImageFormat.NV21) {
+            throw new IllegalArgumentException(
+                    "NV21 format is not supported");
+        }
+
         mNumPlanes = getNumPlanesFromFormat();
 
         nativeInit(new WeakReference<ImageReader>(this), width, height, format, maxImages);
@@ -96,33 +129,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 +209,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,35 +375,46 @@
     /**
      * 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) {
-        mImageListener = listener;
-
-        Looper looper;
-        mHandler = handler;
-        if (listener != null && mHandler == null) {
-            if ((looper = Looper.myLooper()) != null) {
-                mHandler = new Handler();
+    public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
+        synchronized (mListenerLock) {
+            if (listener != null) {
+                Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
+                if (looper == null) {
+                    throw new IllegalArgumentException(
+                            "handler is null but the current thread is not a looper");
+                }
+                if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
+                    mListenerHandler = new ListenerHandler(looper);
+                }
+                mListener = listener;
             } else {
-                throw new IllegalArgumentException(
-                        "Looper doesn't exist in the calling thread");
+                mListener = null;
+                mListenerHandler = null;
             }
         }
     }
 
     /**
      * 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,15 +423,21 @@
     }
 
     /**
-     * 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() {
+        setOnImageAvailableListener(null, null);
         nativeClose();
     }
 
@@ -242,11 +451,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) {
@@ -274,6 +486,9 @@
 
     /**
      * Called from Native code when an Event happens.
+     *
+     * This may be called from an arbitrary Binder thread, so access to the ImageReader must be
+     * synchronized appropriately.
      */
     private static void postEventFromNative(Object selfRef) {
         @SuppressWarnings("unchecked")
@@ -283,16 +498,16 @@
             return;
         }
 
-        if (ir.mHandler != null && ir.mImageListener != null) {
-            ir.mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ir.mImageListener.onImageAvailable(ir);
-                }
-              });
+        final Handler handler;
+        synchronized (ir.mListenerLock) {
+            handler = ir.mListenerHandler;
+        }
+        if (handler != null) {
+            handler.sendEmptyMessage(0);
         }
     }
 
+
     private final int mWidth;
     private final int mHeight;
     private final int mFormat;
@@ -300,15 +515,36 @@
     private final int mNumPlanes;
     private final Surface mSurface;
 
-    private Handler mHandler;
-    private OnImageAvailableListener mImageListener;
+    private final Object mListenerLock = new Object();
+    private OnImageAvailableListener mListener;
+    private ListenerHandler mListenerHandler;
 
     /**
      * This field is used by native code, do not access or modify.
      */
     private long mNativeContext;
 
-    private class SurfaceImage implements android.media.Image {
+    /**
+     * This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
+     */
+    private final class ListenerHandler extends Handler {
+        public ListenerHandler(Looper looper) {
+            super(looper, null, true /*async*/);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            OnImageAvailableListener listener;
+            synchronized (mListenerLock) {
+                listener = mListener;
+            }
+            if (listener != null) {
+                listener.onImageAvailable(ImageReader.this);
+            }
+        }
+    }
+
+    private class SurfaceImage extends android.media.Image {
         public SurfaceImage() {
             mIsImageValid = false;
         }
@@ -404,7 +640,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 +715,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/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 1250cbc..5175830 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -20,7 +20,9 @@
 import android.media.MediaCodecList;
 import android.media.MediaCrypto;
 import android.media.MediaFormat;
+import android.os.Bundle;
 import android.view.Surface;
+
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Map;
@@ -576,7 +578,7 @@
      * Change a video encoder's target bitrate on the fly. The value is an
      * Integer object containing the new bitrate in bps.
      */
-    public static final String PARAMETER_KEY_VIDEO_BITRATE = "videoBitrate";
+    public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
 
     /**
      * Temporarily suspend/resume encoding of input data. While suspended
@@ -598,7 +600,7 @@
     /**
      * Communicate additional parameter changes to the component instance.
      */
-    public final void setParameters(Map<String, Object> params) {
+    public final void setParameters(Bundle params) {
         if (params == null) {
             return;
         }
@@ -607,9 +609,9 @@
         Object[] values = new Object[params.size()];
 
         int i = 0;
-        for (Map.Entry<String, Object> entry: params.entrySet()) {
-            keys[i] = entry.getKey();
-            values[i] = entry.getValue();
+        for (final String key: params.keySet()) {
+            keys[i] = key;
+            values[i] = params.get(key);
             ++i;
         }
 
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index ab686e6..143ddf2 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -138,7 +138,7 @@
     private static final int MSG_PROMOTE_RCC = 6;
     private static final int MSG_RCC_NEW_PLAYBACK_STATE = 7;
     private static final int MSG_RCC_SEEK_REQUEST = 8;
-    private static final int MSG_RCC_UPDATE_METADATA_LONG = 9;
+    private static final int MSG_RCC_UPDATE_METADATA = 9;
 
     // sendMsg() flags
     /** If the msg is already queued, replace it with this one. */
@@ -206,9 +206,9 @@
                             msg.arg1 /* generationId */, ((Long)msg.obj).longValue() /* timeMs */);
                     break;
 
-                case MSG_RCC_UPDATE_METADATA_LONG:
-                    onUpdateRemoteControlClientMetadataLong(msg.arg1 /*genId*/, msg.arg2 /*key*/,
-                            ((Long)msg.obj).longValue() /* value */);
+                case MSG_RCC_UPDATE_METADATA:
+                    onUpdateRemoteControlClientMetadata(msg.arg1 /*genId*/, msg.arg2 /*key*/,
+                            (Rating) msg.obj /* value */);
                     break;
 
                 case MSG_PROMOTE_RCC:
@@ -720,11 +720,7 @@
         }
     }
 
-    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
-        if (keyEvent == null) {
-            return false;
-        }
-        final int keyCode = keyEvent.getKeyCode();
+    protected static boolean isMediaKeyCode(int keyCode) {
         switch (keyCode) {
             case KeyEvent.KEYCODE_MUTE:
             case KeyEvent.KEYCODE_HEADSETHOOK:
@@ -740,11 +736,17 @@
             case KeyEvent.KEYCODE_MEDIA_CLOSE:
             case KeyEvent.KEYCODE_MEDIA_EJECT:
             case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
-                break;
+                return true;
             default:
                 return false;
         }
-        return true;
+    }
+
+    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
+        if (keyEvent == null) {
+            return false;
+        }
+        return MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode());
     }
 
     /**
@@ -2080,20 +2082,20 @@
         }
     }
 
-    protected void updateRemoteControlClientMetadata(int genId, int key, long value) {
-        sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA_LONG, SENDMSG_QUEUE,
-                genId /* arg1 */, key /* arg2 */, Long.valueOf(value) /* obj */, 0 /* delay */);
+    protected void updateRemoteControlClientMetadata(int genId, int key, Rating value) {
+        sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA, SENDMSG_QUEUE,
+                genId /* arg1 */, key /* arg2 */, value /* obj */, 0 /* delay */);
     }
 
-    private void onUpdateRemoteControlClientMetadataLong(int genId, int key, long value) {
-        if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadataLong(genId=" + genId +
-                ", what=" + key + ",val=" + value + ")");
+    private void onUpdateRemoteControlClientMetadata(int genId, int key, Rating value) {
+        if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadata(genId=" + genId +
+                ", what=" + key + ",rating=" + value + ")");
         synchronized(mRCStack) {
             synchronized(mCurrentRcLock) {
                 if ((mCurrentRcClient != null) && (mCurrentRcClientGen == genId)) {
                     try {
                         switch (key) {
-                            case RemoteControlClient.MetadataEditor.LONG_KEY_RATING_BY_USER:
+                            case MediaMetadataEditor.RATING_KEY_BY_USER:
                                 mCurrentRcClient.updateMetadata(genId, key, value);
                                 break;
                             default:
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 16ae43d..0f7906e 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -85,8 +85,8 @@
     public static final String KEY_MIME = "mime";
 
     /**
-     * A key describing the language of the content.
-     * The associated value is a string.
+     * A key describing the language of the content, using either ISO 639-1
+     * or 639-2/T codes.  The associated value is a string.
      */
     public static final String KEY_LANGUAGE = "language";
 
@@ -222,26 +222,36 @@
     public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
 
     /**
-     * A key for boolean AUTOSELECT field. Tracks with AUTOSELECT=true are
-     * considered when automatically selecting a track without specific user
-     * choice (as defined by HLS).
-     * @hide
+     * A key for boolean AUTOSELECT behavior for the track. Tracks with AUTOSELECT=true
+     * are considered when automatically selecting a track without specific user
+     * choice, based on the current locale.
+     * This is currently only used for subtitle tracks, when the user selected
+     * 'Default' for the captioning locale.
+     * The associated value is an integer, where non-0 means TRUE.  This is an optional
+     * field; if not specified, AUTOSELECT defaults to TRUE.
      */
-    public static final String KEY_AUTOSELECT = "autoselect";
+    public static final String KEY_IS_AUTOSELECT = "is-autoselect";
 
     /**
-     * A key for boolean DEFAULT field. The track with DEFAULT=true is selected
-     * in the absence of a specific user choice (as defined by HLS).
-     * @hide
+     * A key for boolean DEFAULT behavior for the track. The track with DEFAULT=true is
+     * selected in the absence of a specific user choice.
+     * This is currently only used for subtitle tracks, when the user selected
+     * 'Default' for the captioning locale.
+     * The associated value is an integer, where non-0 means TRUE.  This is an optional
+     * field; if not specified, DEFAULT is considered to be FALSE.
      */
-    public static final String KEY_DEFAULT = "default";
+    public static final String KEY_IS_DEFAULT = "is-default";
+
 
     /**
-     * A key for boolean FORCED field for subtitle tracks. True if it is a
-     * forced subtitle track.
-     * @hide
+     * A key for the FORCED field for subtitle tracks. True if it is a
+     * forced subtitle track.  Forced subtitle tracks are essential for the
+     * content and are shown even when the user turns off Captions.  They
+     * are used for example to translate foreign/alien dialogs or signs.
+     * The associated value is an integer, where non-0 means TRUE.  This is an
+     * optional field; if not specified, FORCED defaults to FALSE.
      */
-    public static final String KEY_FORCED = "forced";
+    public static final String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
 
     /* package private */ MediaFormat(Map<String, Object> map) {
         mMap = map;
@@ -370,9 +380,10 @@
     /**
      * Creates a minimal subtitle format.
      * @param mime The mime type of the content.
-     * @param language The language of the content.  Specify "und" if language
-     *        information is only included in the content (similarly, if there
-     *        are multiple language tracks in the content.)
+     * @param language The language of the content, using either ISO 639-1 or 639-2/T
+     *        codes.  Specify null or "und" if language information is only included
+     *        in the content.  (This will also work if there are multiple language
+     *        tracks in the content.)
      */
     public static final MediaFormat createSubtitleFormat(
             String mime,
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
new file mode 100644
index 0000000..373ba11
--- /dev/null
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -0,0 +1,462 @@
+/*
+ * 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;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+/**
+ * An abstract class for editing and storing metadata that can be published by
+ * {@link RemoteControlClient}. See the {@link RemoteControlClient#editMetadata(boolean)}
+ * method to instantiate a {@link RemoteControlClient.MetadataEditor} object.
+ */
+public abstract class MediaMetadataEditor {
+
+    private final static String TAG = "MediaMetadataEditor";
+    /**
+     * @hide
+     */
+    protected MediaMetadataEditor() {
+    }
+
+    // Public keys for metadata used by RemoteControlClient and RemoteController.
+    // Note that these keys are defined here, and not in MediaMetadataRetriever
+    // because they are not supported by the MediaMetadataRetriever features.
+    /**
+     * The metadata key for the content artwork / album art.
+     */
+    public final static int BITMAP_KEY_ARTWORK =
+            RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK;
+
+    /**
+     * The metadata key for the content's average rating, not the user's rating.
+     * The value associated with this key is a {@link Rating} instance.
+     * @see #RATING_KEY_BY_USER
+     */
+    public final static int RATING_KEY_BY_OTHERS = 101;
+
+    /**
+     * The metadata key for the content's user rating.
+     * The value associated with this key is a {@link Rating} instance.
+     * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
+     * receiving user rating values through the
+     * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
+     */
+    public final static int RATING_KEY_BY_USER = 0x10000001;
+
+    /**
+     * @hide
+     * Editable key mask
+     */
+    public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
+
+
+    /**
+     * Applies all of the metadata changes that have been set since the MediaMetadataEditor instance
+     * was created or since {@link #clear()} was called.
+     */
+    public abstract void apply();
+
+
+    /**
+     * @hide
+     * Mask of editable keys.
+     */
+    protected long mEditableKeys;
+
+    /**
+     * @hide
+     */
+    protected boolean mMetadataChanged = false;
+
+    /**
+     * @hide
+     */
+    protected boolean mApplied = false;
+
+    /**
+     * @hide
+     */
+    protected boolean mArtworkChanged = false;
+
+    /**
+     * @hide
+     */
+    protected Bitmap mEditorArtwork;
+
+    /**
+     * @hide
+     */
+    protected Bundle mEditorMetadata;
+
+
+    /**
+     * Clears all the pending metadata changes set since the MediaMetadataEditor instance was
+     * created or since this method was last called.
+     * Note that clearing the metadata doesn't reset the editable keys
+     * (use {@link #removeEditableKeys()} instead).
+     */
+    public synchronized void clear() {
+        if (mApplied) {
+            Log.e(TAG, "Can't clear a previously applied MediaMetadataEditor");
+            return;
+        }
+        mEditorMetadata.clear();
+        mEditorArtwork = null;
+    }
+
+    /**
+     * Flags the given key as being editable.
+     * This should only be used by metadata publishers, such as {@link RemoteControlClient},
+     * which will declare the metadata field as eligible to be updated, with new values
+     * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
+     * @param key the type of metadata that can be edited. The supported key is
+     *     {@link #RATING_KEY_BY_USER}.
+     */
+    public synchronized void addEditableKey(int key) {
+        if (mApplied) {
+            Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
+            return;
+        }
+        // only one editable key at the moment, so we're not wasting memory on an array
+        // of editable keys to check the validity of the key, just hardcode the supported key.
+        if (key == RATING_KEY_BY_USER) {
+            mEditableKeys |= (KEY_EDITABLE_MASK & key);
+            mMetadataChanged = true;
+        } else {
+            Log.e(TAG, "Metadata key " + key + " cannot be edited");
+        }
+    }
+
+    /**
+     * Causes all metadata fields to be read-only.
+     */
+    public synchronized void removeEditableKeys() {
+        if (mApplied) {
+            Log.e(TAG, "Can't remove all editable keys of a previously applied MetadataEditor");
+            return;
+        }
+        if (mEditableKeys != 0) {
+            mEditableKeys = 0;
+            mMetadataChanged = true;
+        }
+    }
+
+    /**
+     * Retrieves the keys flagged as editable.
+     * @return null if there are no editable keys, or an array containing the keys.
+     */
+    public synchronized int[] getEditableKeys() {
+        // only one editable key supported here
+        if (mEditableKeys == RATING_KEY_BY_USER) {
+            int[] keys = { RATING_KEY_BY_USER };
+            return keys;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Adds textual information.
+     * Note that none of the information added after {@link #apply()} has been called,
+     * will be available to consumers of metadata stored by the MediaMetadataEditor.
+     * @param key The identifier of a the metadata field to set. Valid values are
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
+     * @param value The text for the given key, or {@code null} to signify there is no valid
+     *      information for the field.
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     */
+    public synchronized MediaMetadataEditor putString(int key, String value)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+            throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+        }
+        mEditorMetadata.putString(String.valueOf(key), value);
+        mMetadataChanged = true;
+        return this;
+    }
+
+    /**
+     * Adds numerical information.
+     * Note that none of the information added after {@link #apply()} has been called
+     * will be available to consumers of metadata stored by the MediaMetadataEditor.
+     * @param key the identifier of a the metadata field to set. Valid values are
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
+     *      expressed in milliseconds),
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+     * @param value The long value for the given key
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     * @throws IllegalArgumentException
+     */
+    public synchronized MediaMetadataEditor putLong(int key, long value)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+            throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+        }
+        mEditorMetadata.putLong(String.valueOf(key), value);
+        mMetadataChanged = true;
+        return this;
+    }
+
+    /**
+     * Adds image.
+     * @param key the identifier of the bitmap to set. The only valid value is
+     *      {@link #BITMAP_KEY_ARTWORK}
+     * @param bitmap The bitmap for the artwork, or null if there isn't any.
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     * @throws IllegalArgumentException
+     * @see android.graphics.Bitmap
+     */
+    public synchronized MediaMetadataEditor putBitmap(int key, Bitmap bitmap)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        if (key != BITMAP_KEY_ARTWORK) {
+            throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+        }
+        mEditorArtwork = bitmap;
+        mArtworkChanged = true;
+        return this;
+    }
+
+    /**
+     * Adds information stored as an instance.
+     * Note that none of the information added after {@link #apply()} has been called
+     * will be available to consumers of metadata stored by the MediaMetadataEditor.
+     * @param key the identifier of a the metadata field to set. Valid keys for a:
+     *     <ul>
+     *     <li>{@link Bitmap} object are {@link #BITMAP_KEY_ARTWORK},</li>
+     *     <li>{@link String} object are the same as for {@link #putString(int, String)}</li>
+     *     <li>{@link Long} object are the same as for {@link #putLong(int, long)}</li>
+     *     <li>{@link Rating} object are {@link #RATING_KEY_BY_OTHERS}
+     *         and {@link #RATING_KEY_BY_USER}.</li>
+     *     </ul>
+     * @param value the metadata to add.
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     * @throws IllegalArgumentException
+     */
+    public synchronized MediaMetadataEditor putObject(int key, Object value)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        switch(METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+            case METADATA_TYPE_LONG:
+                if (value instanceof Long) {
+                    return putLong(key, ((Long)value).longValue());
+                } else {
+                    throw(new IllegalArgumentException("Not a non-null Long for key "+ key));
+                }
+            case METADATA_TYPE_STRING:
+                if ((value == null) || (value instanceof String)) {
+                    return putString(key, (String) value);
+                } else {
+                    throw(new IllegalArgumentException("Not a String for key "+ key));
+                }
+            case METADATA_TYPE_RATING:
+                mEditorMetadata.putParcelable(String.valueOf(key), (Parcelable)value);
+                mMetadataChanged = true;
+                break;
+            case METADATA_TYPE_BITMAP:
+                if ((value == null) || (value instanceof Bitmap))  {
+                    return putBitmap(key, (Bitmap) value);
+                } else {
+                    throw(new IllegalArgumentException("Not a Bitmap for key "+ key));
+                }
+            default:
+                throw(new IllegalArgumentException("Invalid key "+ key));
+        }
+        return this;
+    }
+
+
+    /**
+     * Returns the long value for the key.
+     * @param key one of the keys supported in {@link #putLong(int, long)}
+     * @param defaultValue the value returned if the key is not present
+     * @return the long value for the key, or the supplied default value if the key is not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized long getLong(int key, long defaultValue)
+            throws IllegalArgumentException {
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+            throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+        }
+        return mEditorMetadata.getLong(String.valueOf(key), defaultValue);
+    }
+
+    /**
+     * Returns the {@link String} value for the key.
+     * @param key one of the keys supported in {@link #putString(int, String)}
+     * @param defaultValue the value returned if the key is not present
+     * @return the {@link String} value for the key, or the supplied default value if the key is
+     *     not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized String getString(int key, String defaultValue)
+            throws IllegalArgumentException {
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+            throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+        }
+        return mEditorMetadata.getString(String.valueOf(key), defaultValue);
+    }
+
+    /**
+     * Returns the {@link Bitmap} value for the key.
+     * @param key the {@link #BITMAP_KEY_ARTWORK} key
+     * @param defaultValue the value returned if the key is not present
+     * @return the {@link Bitmap} value for the key, or the supplied default value if the key is
+     *     not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized Bitmap getBitmap(int key, Bitmap defaultValue)
+            throws IllegalArgumentException {
+        if (key != BITMAP_KEY_ARTWORK) {
+            throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+        }
+        return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+    }
+
+    /**
+     * Returns an object representation of the value for the key
+     * @param key one of the keys supported in {@link #putObject(int, Object)}
+     * @param defaultValue the value returned if the key is not present
+     * @return the object for the key, as a {@link Long}, {@link Bitmap}, {@link String}, or
+     *     {@link Rating} depending on the key value, or the supplied default value if the key is
+     *     not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized Object getObject(int key, Object defaultValue)
+            throws IllegalArgumentException {
+        switch (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+            case METADATA_TYPE_LONG:
+                if (mEditorMetadata.containsKey(String.valueOf(key))) {
+                    return mEditorMetadata.getLong(String.valueOf(key));
+                } else {
+                    return defaultValue;
+                }
+            case METADATA_TYPE_STRING:
+                if (mEditorMetadata.containsKey(String.valueOf(key))) {
+                    return mEditorMetadata.getString(String.valueOf(key));
+                } else {
+                    return defaultValue;
+                }
+            case METADATA_TYPE_RATING:
+                if (mEditorMetadata.containsKey(String.valueOf(key))) {
+                    return mEditorMetadata.getParcelable(String.valueOf(key));
+                } else {
+                    return defaultValue;
+                }
+            case METADATA_TYPE_BITMAP:
+                // only one key for Bitmap supported, value is not stored in mEditorMetadata Bundle
+                if (key == BITMAP_KEY_ARTWORK) {
+                    return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+                } // else: fall through to invalid key handling
+            default:
+                throw(new IllegalArgumentException("Invalid key "+ key));
+        }
+    }
+
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_INVALID = -1;
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_LONG = 0;
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_STRING = 1;
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_BITMAP = 2;
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_RATING = 3;
+
+    /**
+     * @hide
+     */
+    protected static final SparseIntArray METADATA_KEYS_TYPE;
+
+    static {
+        METADATA_KEYS_TYPE = new SparseIntArray(17);
+        // NOTE: if adding to the list below, make sure you increment the array initialization size
+        // keys with long values
+        METADATA_KEYS_TYPE.put(
+                MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_TYPE_LONG);
+        // keys with String values
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(
+                MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(
+                MediaMetadataRetriever.METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_TYPE_STRING);
+        // keys with Bitmap values
+        METADATA_KEYS_TYPE.put(BITMAP_KEY_ARTWORK, METADATA_TYPE_BITMAP);
+        // keys with Rating values
+        METADATA_KEYS_TYPE.put(RATING_KEY_BY_OTHERS, METADATA_TYPE_RATING);
+        METADATA_KEYS_TYPE.put(RATING_KEY_BY_USER, METADATA_TYPE_RATING);
+    }
+}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7acf8af..deba2cc 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1606,9 +1606,9 @@
             } else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
                 mFormat = MediaFormat.createSubtitleFormat(
                     MEDIA_MIMETYPE_TEXT_VTT, language);
-                mFormat.setInteger(MediaFormat.KEY_AUTOSELECT, in.readInt());
-                mFormat.setInteger(MediaFormat.KEY_DEFAULT, in.readInt());
-                mFormat.setInteger(MediaFormat.KEY_FORCED, in.readInt());
+                mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
+                mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
+                mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
             } else {
                 mFormat = new MediaFormat();
                 mFormat.setString(MediaFormat.KEY_LANGUAGE, language);
@@ -1638,9 +1638,9 @@
             dest.writeString(getLanguage());
 
             if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
-                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_AUTOSELECT));
-                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_DEFAULT));
-                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_FORCED));
+                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
+                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
+                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
             }
         }
 
@@ -1765,15 +1765,21 @@
     @Override
     public void onSubtitleTrackSelected(SubtitleTrack track) {
         if (mSelectedSubtitleTrackIndex >= 0) {
-            deselectTrack(mSelectedSubtitleTrackIndex);
+            try {
+                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
+            } catch (IllegalStateException e) {
+            }
+            mSelectedSubtitleTrackIndex = -1;
         }
-        mSelectedSubtitleTrackIndex = -1;
         setOnSubtitleDataListener(null);
         for (int i = 0; i < mInbandSubtitleTracks.length; i++) {
             if (mInbandSubtitleTracks[i] == track) {
                 Log.v(TAG, "Selecting subtitle track " + i);
-                selectTrack(i);
                 mSelectedSubtitleTrackIndex = i;
+                try {
+                    selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
+                } catch (IllegalStateException e) {
+                }
                 setOnSubtitleDataListener(mSubtitleDataListener);
                 break;
             }
@@ -2046,13 +2052,30 @@
 
     private void selectOrDeselectTrack(int index, boolean select)
             throws IllegalStateException {
-        // ignore out-of-band tracks
-        TrackInfo[] trackInfo = getInbandTrackInfo();
-        if (index >= trackInfo.length &&
-                index < trackInfo.length + mOutOfBandSubtitleTracks.size()) {
+        // handle subtitle track through subtitle controller
+        SubtitleTrack track = null;
+        if (index < mInbandSubtitleTracks.length) {
+            track = mInbandSubtitleTracks[index];
+        } else if (index < mInbandSubtitleTracks.length + mOutOfBandSubtitleTracks.size()) {
+            track = mOutOfBandSubtitleTracks.get(index - mInbandSubtitleTracks.length);
+        }
+
+        if (mSubtitleController != null && track != null) {
+            if (select) {
+                mSubtitleController.selectTrack(track);
+            } else if (mSubtitleController.getSelectedTrack() == track) {
+                mSubtitleController.selectTrack(null);
+            } else {
+                Log.w(TAG, "trying to deselect track that was not selected");
+            }
             return;
         }
 
+        selectOrDeselectInbandTrack(index, select);
+    }
+
+    private void selectOrDeselectInbandTrack(int index, boolean select)
+            throws IllegalStateException {
         Parcel request = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
diff --git a/core/res/res/values-land/refs.xml b/media/java/android/media/Rating.aidl
similarity index 62%
copy from core/res/res/values-land/refs.xml
copy to media/java/android/media/Rating.aidl
index cda38cf..1dc336a 100644
--- a/core/res/res/values-land/refs.xml
+++ b/media/java/android/media/Rating.aidl
@@ -1,20 +1,19 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2013, The Android Open Source Project
+/*
+ * 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
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT 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.media;
+
+parcelable Rating;
diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java
new file mode 100644
index 0000000..82c0392
--- /dev/null
+++ b/media/java/android/media/Rating.java
@@ -0,0 +1,284 @@
+/*
+ * 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;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class to encapsulate rating information used as content metadata.
+ * A rating is defined by its rating style (see {@link #RATING_HEART},
+ * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+ * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
+ * be defined as "unrated"), both of which are defined when the rating instance is constructed
+ * through one of the factory methods.
+ */
+public final class Rating implements Parcelable {
+
+    private final static String TAG = "Rating";
+
+    /**
+     * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
+     * indicate the content referred to is a favorite (or not).
+     */
+    public final static int RATING_HEART = 1;
+
+    /**
+     * A rating style for "thumb up" vs "thumb down".
+     */
+    public final static int RATING_THUMB_UP_DOWN = 2;
+
+    /**
+     * A rating style with 0 to 3 stars.
+     */
+    public final static int RATING_3_STARS = 3;
+
+    /**
+     * A rating style with 0 to 4 stars.
+     */
+    public final static int RATING_4_STARS = 4;
+
+    /**
+     * A rating style with 0 to 5 stars.
+     */
+    public final static int RATING_5_STARS = 5;
+
+    /**
+     * A rating style expressed as a percentage.
+     */
+    public final static int RATING_PERCENTAGE = 6;
+
+    private final static float RATING_NOT_RATED = -1.0f;
+
+    private final int mRatingStyle;
+
+    private final float mRatingValue;
+
+    private Rating(int ratingStyle, float rating) {
+        mRatingStyle = ratingStyle;
+        mRatingValue = rating;
+    }
+
+
+    /**
+     * @hide
+     */
+    @Override
+    public String toString () {
+        return "Rating:style=" + mRatingStyle + " rating="
+                + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue));
+    }
+
+    @Override
+    public int describeContents() {
+        return mRatingStyle;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRatingStyle);
+        dest.writeFloat(mRatingValue);
+    }
+
+    public static final Parcelable.Creator<Rating> CREATOR
+            = new Parcelable.Creator<Rating>() {
+        /**
+         * Rebuilds a Rating previously stored with writeToParcel().
+         * @param p    Parcel object to read the Rating from
+         * @return a new Rating created from the data in the parcel
+         */
+        public Rating createFromParcel(Parcel p) {
+            return new Rating(p.readInt(), p.readFloat());
+        }
+        public Rating[] newArray(int size) {
+            return new Rating[size];
+        }
+    };
+
+    /**
+     * Return a Rating instance with no rating.
+     * Create and return a new Rating instance with no rating known for the given
+     * rating style.
+     * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+     *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+     *    or {@link #RATING_PERCENTAGE}.
+     * @return null if an invalid rating style is passed, a new Rating instance otherwise.
+     */
+    public static Rating newUnratedRating(int ratingStyle) {
+        switch(ratingStyle) {
+            case RATING_HEART:
+            case RATING_THUMB_UP_DOWN:
+            case RATING_3_STARS:
+            case RATING_4_STARS:
+            case RATING_5_STARS:
+            case RATING_PERCENTAGE:
+                return new Rating(ratingStyle, RATING_NOT_RATED);
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Return a Rating instance with a heart-based rating.
+     * Create and return a new Rating instance with a rating style of {@link #RATING_HEART},
+     * and a heart-based rating.
+     * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
+     * @return a new Rating instance.
+     */
+    public static Rating newHeartRating(boolean hasHeart) {
+        return new Rating(RATING_HEART, hasHeart ? 1.0f : 0.0f);
+    }
+
+    /**
+     * Return a Rating instance with a thumb-based rating.
+     * Create and return a new Rating instance with a {@link #RATING_THUMB_UP_DOWN}
+     * rating style, and a "thumb up" or "thumb down" rating.
+     * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
+     * @return a new Rating instance.
+     */
+    public static Rating newThumbRating(boolean thumbIsUp) {
+        return new Rating(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f);
+    }
+
+    /**
+     * Return a Rating instance with a star-based rating.
+     * Create and return a new Rating instance with one of the star-base rating styles
+     * and the given integer or fractional number of stars. Non integer values can for instance
+     * be used to represent an average rating value, which might not be an integer number of stars.
+     * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+     *     {@link #RATING_5_STARS}.
+     * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
+     *     the rating style.
+     * @return null if the rating style is invalid, or the rating is out of range,
+     *     a new Rating instance otherwise.
+     */
+    public static Rating newStarRating(int starRatingStyle, float starRating) {
+        float maxRating = -1.0f;
+        switch(starRatingStyle) {
+            case RATING_3_STARS:
+                maxRating = 3.0f;
+                break;
+            case RATING_4_STARS:
+                maxRating = 4.0f;
+                break;
+            case RATING_5_STARS:
+                maxRating = 5.0f;
+                break;
+            default:
+                Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
+                        return null;
+        }
+        if ((starRating < 0.0f) || (starRating > maxRating)) {
+            Log.e(TAG, "Trying to set out of range star-based rating");
+            return null;
+        }
+        return new Rating(starRatingStyle, starRating);
+    }
+
+    /**
+     * Return a Rating instance with a percentage-based rating.
+     * Create and return a new Rating instance with a {@link #RATING_PERCENTAGE}
+     * rating style, and a rating of the given percentage.
+     * @param percent the value of the rating
+     * @return null if the rating is out of range, a new Rating instance otherwise.
+     */
+    public static Rating newPercentageRating(float percent) {
+        if ((percent < 0.0f) || (percent > 100.0f)) {
+            Log.e(TAG, "Invalid percentage-based rating value");
+            return null;
+        } else {
+            return new Rating(RATING_PERCENTAGE, percent);
+        }
+    }
+
+    /**
+     * Return whether there is a rating value available.
+     * @return true if the instance was not created with {@link #newUnratedRating(int)}.
+     */
+    public boolean isRated() {
+        return mRatingValue >= 0.0f;
+    }
+
+    /**
+     * Return the rating style.
+     * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+     *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+     *    or {@link #RATING_PERCENTAGE}.
+     */
+    public int getRatingStyle() {
+        return mRatingStyle;
+    }
+
+    /**
+     * Return whether the rating is "heart selected".
+     * @return true if the rating is "heart selected", false if the rating is "heart unselected",
+     *    if the rating style is not {@link #RATING_HEART} or if it is unrated.
+     */
+    public boolean hasHeart() {
+        if (mRatingStyle != RATING_HEART) {
+            return false;
+        } else {
+            return (mRatingValue == 1.0f);
+        }
+    }
+
+    /**
+     * Return whether the rating is "thumb up".
+     * @return true if the rating is "thumb up", false if the rating is "thumb down",
+     *    if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated.
+     */
+    public boolean isThumbUp() {
+        if (mRatingStyle != RATING_THUMB_UP_DOWN) {
+            return false;
+        } else {
+            return (mRatingValue == 1.0f);
+        }
+    }
+
+    /**
+     * Return the star-based rating value.
+     * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+     *    not star-based, or if it is unrated.
+     */
+    public float getStarRating() {
+        switch (mRatingStyle) {
+            case RATING_3_STARS:
+            case RATING_4_STARS:
+            case RATING_5_STARS:
+                if (isRated()) {
+                    return mRatingValue;
+                }
+            default:
+                return -1.0f;
+        }
+    }
+
+    /**
+     * Return the percentage-based rating value.
+     * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+     *    not percentage-based, or if it is unrated.
+     */
+    public float getPercentRating() {
+        if ((mRatingStyle != RATING_PERCENTAGE) || !isRated()) {
+            return -1.0f;
+        } else {
+            return mRatingValue;
+        }
+    }
+}
\ No newline at end of file
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 58f5d55..7613c89 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -30,6 +30,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -297,8 +298,8 @@
      * Flag indicating a RemoteControlClient supports ratings.
      * This flag must be set in order for components that display the RemoteControlClient
      * information, to display ratings information, and, if ratings are declared editable
-     * (by calling {@link MetadataEditor#addEditableKey(int)} with the
-     * {@link MetadataEditor#LONG_KEY_RATING_BY_USER} key), it will enable the user to rate
+     * (by calling {@link MediaMetadataEditor#addEditableKey(int)} with the
+     * {@link MediaMetadataEditor#RATING_KEY_BY_USER} key), it will enable the user to rate
      * the media, with values being received through the interface set with
      * {@link #setMetadataUpdateListener(OnMetadataUpdateListener)}.
      * @see #setTransportControlFlags(int)
@@ -385,27 +386,6 @@
         mEventHandler = new EventHandler(this, looper);
     }
 
-    private static final int[] METADATA_KEYS_TYPE_STRING = {
-        MediaMetadataRetriever.METADATA_KEY_ALBUM,
-        MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
-        MediaMetadataRetriever.METADATA_KEY_TITLE,
-        MediaMetadataRetriever.METADATA_KEY_ARTIST,
-        MediaMetadataRetriever.METADATA_KEY_AUTHOR,
-        MediaMetadataRetriever.METADATA_KEY_COMPILATION,
-        MediaMetadataRetriever.METADATA_KEY_COMPOSER,
-        MediaMetadataRetriever.METADATA_KEY_DATE,
-        MediaMetadataRetriever.METADATA_KEY_GENRE,
-        MediaMetadataRetriever.METADATA_KEY_TITLE,
-        MediaMetadataRetriever.METADATA_KEY_WRITER };
-    private static final int[] METADATA_KEYS_TYPE_LONG = {
-        MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
-        MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
-        MediaMetadataRetriever.METADATA_KEY_DURATION,
-        MediaMetadataRetriever.METADATA_KEY_YEAR,
-        MetadataEditor.LONG_KEY_RATING_TYPE,
-        MetadataEditor.LONG_KEY_RATING_BY_OTHERS,
-        MetadataEditor.LONG_KEY_RATING_BY_USER};
-
     /**
      * Class used to modify metadata in a {@link RemoteControlClient} object.
      * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
@@ -414,28 +394,7 @@
      * for the associated client. Once the metadata has been "applied", you cannot reuse this
      * instance of the MetadataEditor.
      */
-    public class MetadataEditor {
-        /**
-         * Mask of editable keys.
-         */
-        private long mEditableKeys;
-        /**
-         * @hide
-         */
-        protected boolean mMetadataChanged;
-        /**
-         * @hide
-         */
-        protected boolean mArtworkChanged;
-        /**
-         * @hide
-         */
-        protected Bitmap mEditorArtwork;
-        /**
-         * @hide
-         */
-        protected Bundle mEditorMetadata;
-        private boolean mApplied = false;
+    public class MetadataEditor extends MediaMetadataEditor {
 
         // only use RemoteControlClient.editMetadata() to get a MetadataEditor instance
         private MetadataEditor() { }
@@ -450,73 +409,10 @@
          * The metadata key for the content artwork / album art.
          */
         public final static int BITMAP_KEY_ARTWORK = 100;
-        /**
-         * The metadata key qualifying the content rating.
-         * The value associated with this key may be: {@link #RATING_HEART},
-         * {@link #RATING_THUMB_UP_DOWN}, or a non-null positive integer expressing a maximum
-         * number of "stars" for the rating, for which a typical value is 3 or 5.
-         */
-        public final static int LONG_KEY_RATING_TYPE = 101;
-        /**
-         * The metadata key for the content's average rating, not the user's rating.
-         * The value associated with this key may be: an integer value between 0 and 100,
-         * or {@link #RATING_NOT_RATED} to express that no average rating is available.
-         * <p></p>
-         * Note that a rating value up to 100 is not incompatible with a rating type using up
-         * to 5 stars for instance, as the average may be an non-integer number of stars.
-         * <p></p>
-         * When the rating type is:
-         * <ul>
-         * <li>{@link #RATING_HEART}, a rating of 51 to 100 means "heart selected",</li>
-         * <li>{@link #RATING_THUMB_UP_DOWN}, a rating of 0 to 50 means "thumb down",
-         *     51 to 100 means "thumb up"</li>
-         * <li>a non-null positive integer, the rating value is mapped to the number of stars, e.g.
-         *     with a maximum of 5 stars, a rating of 0 maps to 0 stars, 1 to 20 maps to 1 star,
-         *     21 to 40 maps to 2 stars, etc.</li>
-         * </ul>
-         * @see #LONG_KEY_RATING_BY_USER
-         */
-        public final static int LONG_KEY_RATING_BY_OTHERS = 102;
-
-        // editable keys
-        /**
-         * @hide
-         * Editable key mask
-         */
-        public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
-        /**
-         * The metadata key for the content's user rating.
-         * The value associated with this key may be: an integer value between 0 and 100,
-         * or {@link #RATING_NOT_RATED} to express that the user hasn't rated this content.
-         * Rules for the interpretation of the rating value according to the rating style are
-         * the same as for {@link #LONG_KEY_RATING_BY_OTHERS}.
-         * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
-         * receiving user rating values through the
-         * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
-         */
-        public final static int LONG_KEY_RATING_BY_USER = 0x10000001;
-
-        /**
-         * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
-         * indicate the content referred to is a favorite (or not).
-         * @see #LONG_KEY_RATING_TYPE
-         */
-        public final static long RATING_HEART = -1;
-        /**
-         * A rating style for "thumb up" vs "thumb down".
-         * @see #LONG_KEY_RATING_TYPE
-         */
-        public final static long RATING_THUMB_UP_DOWN = -2;
-        /**
-         * A rating value indicating no rating is available.
-         * @see #LONG_KEY_RATING_BY_OTHERS
-         * @see #LONG_KEY_RATING_BY_USER
-         */
-        public final static long RATING_NOT_RATED = -101;
 
         /**
          * @hide
-         * TODO(jmtrivi) have lockscreen and music move to the new key name
+         * TODO(jmtrivi) have lockscreen move to the new key name and remove
          */
         public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
 
@@ -543,15 +439,7 @@
          */
         public synchronized MetadataEditor putString(int key, String value)
                 throws IllegalArgumentException {
-            if (mApplied) {
-                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
-                return this;
-            }
-            if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) {
-                throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
-            }
-            mEditorMetadata.putString(String.valueOf(key), value);
-            mMetadataChanged = true;
+            super.putString(key, value);
             return this;
         }
 
@@ -564,9 +452,7 @@
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
          *      expressed in milliseconds),
-         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR},
-         *      {@link #LONG_KEY_RATING_BY_OTHERS}, {@link #LONG_KEY_RATING_BY_USER},
-         *      {@link #LONG_KEY_RATING_TYPE}.
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
          * @param value The long value for the given key
          * @return Returns a reference to the same MetadataEditor object, so you can chain put
          *      calls together.
@@ -574,15 +460,7 @@
          */
         public synchronized MetadataEditor putLong(int key, long value)
                 throws IllegalArgumentException {
-            if (mApplied) {
-                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
-                return this;
-            }
-            if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) {
-                throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
-            }
-            mEditorMetadata.putLong(String.valueOf(key), value);
-            mMetadataChanged = true;
+            super.putLong(key, value);
             return this;
         }
 
@@ -596,69 +474,22 @@
          * @throws IllegalArgumentException
          * @see android.graphics.Bitmap
          */
+        @Override
         public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
                 throws IllegalArgumentException {
-            if (mApplied) {
-                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
-                return this;
-            }
-            if (key != BITMAP_KEY_ARTWORK) {
-                throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
-            }
-            mEditorArtwork = bitmap;
-            mArtworkChanged = true;
+            super.putBitmap(key, bitmap);
             return this;
         }
 
         /**
-         * Clears all the metadata that has been set since the MetadataEditor instance was
-         *     created with {@link RemoteControlClient#editMetadata(boolean)}.
+         * Clears all the metadata that has been set since the MetadataEditor instance was created
+         * (with {@link RemoteControlClient#editMetadata(boolean)}).
          * Note that clearing the metadata doesn't reset the editable keys
-         * (use {@link #clearEditableKeys()} instead).
+         * (use {@link MediaMetadataEditor#removeEditableKeys()} instead).
          */
+        @Override
         public synchronized void clear() {
-            if (mApplied) {
-                Log.e(TAG, "Can't clear a previously applied MetadataEditor");
-                return;
-            }
-            mEditorMetadata.clear();
-            mEditorArtwork = null;
-        }
-
-        /**
-         * Flag the given key as being editable.
-         * This will declare the metadata field as eligible to be updated, with new values
-         * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
-         * @param key the type of metadata that can be edited. The supported key is
-         *     {@link #LONG_KEY_RATING_BY_USER}.
-         */
-        public synchronized void addEditableKey(int key) {
-            if (mApplied) {
-                Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
-                return;
-            }
-            // only one editable key at the moment, so we're not wasting memory on an array
-            // of editable keys to check the validity of the key, just hardcode the supported key.
-            if (key == MetadataEditor.LONG_KEY_RATING_BY_USER) {
-                mEditableKeys |= (MetadataEditor.KEY_EDITABLE_MASK & key);
-                mMetadataChanged = true;
-            } else {
-                Log.e(TAG, "Metadata key " + key + " cannot be edited");
-            }
-        }
-
-        /**
-         * Causes all metadata fields to be read-only.
-         */
-        public synchronized void clearEditableKeys() {
-            if (mApplied) {
-                Log.e(TAG, "Can't clear editable keys of a previously applied MetadataEditor");
-                return;
-            }
-            if (mEditableKeys != 0) {
-                mEditableKeys = 0;
-                mMetadataChanged = true;
-            }
+            super.clear();
         }
 
         /**
@@ -881,30 +712,17 @@
     /**
      * Interface definition for a callback to be invoked when one of the metadata values has
      * been updated.
+     * Implement this interface to receive metadata updates after registering your listener
+     * through {@link RemoteControlClient#setMetadataUpdateListener(OnMetadataUpdateListener)}.
      */
-    public interface OnMetadataUpdateListener  {
+    public interface OnMetadataUpdateListener {
         /**
          * Called on the implementer to notify that the metadata field for the given key has
-         * been updated to the new value of type <code>long</long>.
-         * @param key the identifier of the updated metadata field of type <code>long</long>.
-         * @param newValue the new <code>long</long> value for the key
+         * been updated to the new value.
+         * @param key the identifier of the updated metadata field.
+         * @param newValue the Object storing the new value for the key.
          */
-        void onMetadataUpdateLong(int key, long newValue);
-        /**
-         * Called on the implementer to notify that the metadata field for the given key has
-         * been updated to the new <code>String</long>.
-         * @param key the identifier of the updated metadata field of type <code>String</long>.
-         * @param newValue the new <code>String</long> value for the key
-         */
-        void onMetadataUpdateString(int key, String newValue);
-        /**
-         * Called on the implementer to notify that the metadata field for the given key has
-         * been updated to the new {@link android.graphics.Bitmap}.
-         * @param key the identifier of the updated metadata field of type
-         *     {@link android.graphics.Bitmap}.
-         * @param newValue the new {@link android.graphics.Bitmap} for the key
-         */
-        void onMetadataUpdateBitmap(int key, Bitmap newValue);
+        public abstract void onMetadataUpdate(int key, Object newValue);
     }
 
     /**
@@ -1338,12 +1156,11 @@
             }
         }
 
-        public void updateMetadata(int generationId, int key, long value) {
+        public void updateMetadata(int generationId, int key, Rating value) {
             // only post messages, we can't block here
             if (mEventHandler != null) {
                 mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_UPDATE_METADATA_LONG, generationId /* arg1 */, key /* arg2*/,
-                        new Long(value)));
+                        MSG_UPDATE_METADATA, generationId /* arg1 */, key /* arg2*/, value));
             }
         }
     };
@@ -1389,7 +1206,7 @@
     private final static int MSG_SEEK_TO = 10;
     private final static int MSG_POSITION_DRIFT_CHECK = 11;
     private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12;
-    private final static int MSG_UPDATE_METADATA_LONG = 13;
+    private final static int MSG_UPDATE_METADATA = 13;
 
     private class EventHandler extends Handler {
         public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1443,8 +1260,8 @@
                 case MSG_DISPLAY_WANTS_POS_SYNC:
                     onDisplayWantsSync((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
                     break;
-                case MSG_UPDATE_METADATA_LONG:
-                    onUpdateMetadata(msg.arg1, msg.arg2, ((Long)msg.obj).longValue());
+                case MSG_UPDATE_METADATA:
+                    onUpdateMetadata(msg.arg1, msg.arg2, msg.obj);
                     break;
                 default:
                     Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
@@ -1725,10 +1542,10 @@
         }
     }
 
-    private void onUpdateMetadata(int generationId, int key, long value) {
+    private void onUpdateMetadata(int generationId, int key, Object value) {
         synchronized (mCacheLock) {
             if ((mCurrentClientGenId == generationId) && (mMetadataUpdateListener != null)) {
-                mMetadataUpdateListener.onMetadataUpdateLong(key, value);
+                mMetadataUpdateListener.onMetadataUpdate(key, value);
             }
         }
     }
@@ -1771,24 +1588,6 @@
         return bitmap;
     }
 
-    /**
-     *  Fast routine to go through an array of allowed keys and return whether the key is part
-     *  of that array
-     * @param key the key value
-     * @param validKeys the array of valid keys for a given type
-     * @return true if the key is part of the array, false otherwise
-     */
-    private static boolean validTypeForKey(int key, int[] validKeys) {
-        try {
-            for (int i = 0 ; ; i++) {
-                if (key == validKeys[i]) {
-                    return true;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            return false;
-        }
-    }
 
     /**
      * Returns whether, for the given playback state, the playback position is expected to
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
new file mode 100644
index 0000000..6266160
--- /dev/null
+++ b/media/java/android/media/RemoteController.java
@@ -0,0 +1,796 @@
+/*
+ * 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;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.media.IRemoteControlDisplay;
+import android.media.MediaMetadataEditor;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.KeyEvent;
+
+/**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * The RemoteController class is used to control media playback, display and update media metadata
+ * and playback status, published by applications using the {@link RemoteControlClient} class.
+ * <p>
+ * A RemoteController shall be registered through
+ * {@link AudioManager#registerRemoteController(RemoteController)} in order for the system to send
+ * media event updates to the listener set in
+ * {@link #setOnClientUpdateListener(OnClientUpdateListener)}. This listener is a subclass of
+ * the {@link OnClientUpdateListener} abstract class. Override its methods to receive the
+ * information published by the active {@link RemoteControlClient} instances.
+ * By default an {@link OnClientUpdateListener} implementation will not receive bitmaps for album
+ * art. Use {@link #setBitmapConfiguration(boolean, int, int)} to receive images as well.
+ * <p>
+ * A RemoteController can also be used without being registered, when it is only meant to send
+ * media key events (for play or stop events for instance),
+ * with {@link #sendMediaKeyEvent(KeyEvent)}.
+ */
+public class RemoteController
+{
+    private final static int MAX_BITMAP_DIMENSION = 512;
+    private final static int TRANSPORT_UNKNOWN = 0;
+    private RcDisplay mRcd;
+    private final static String TAG = "RemoteController";
+    private final static boolean DEBUG = false;
+    private final static Object mGenLock = new Object();
+    private final static Object mInfoLock = new Object();
+    private Context mContext;
+    private AudioManager mAudioManager;
+    private MetadataEditor mMetadataEditor;
+
+    /**
+     * Synchronized on mGenLock
+     */
+    private int mClientGenerationIdCurrent = 0;
+
+    /**
+     * Synchronized on mInfoLock
+     */
+    private boolean mIsRegistered = false;
+    private PendingIntent mClientPendingIntentCurrent;
+    private OnClientUpdateListener mOnClientUpdateListener;
+    private PlaybackInfo mLastPlaybackInfo;
+    private int mLastTransportControlFlags = TRANSPORT_UNKNOWN;
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param ctxt non-null {@link Context}
+     * @throws java.lang.IllegalArgumentException
+     */
+    public RemoteController(Context ctxt) throws IllegalArgumentException {
+        if (ctxt == null) {
+            throw new IllegalArgumentException("Invalid null Context");
+        }
+        Looper looper;
+        if ((looper = Looper.myLooper()) != null) {
+            mEventHandler = new EventHandler(this, looper);
+        } else if ((looper = Looper.getMainLooper()) != null) {
+            mEventHandler = new EventHandler(this, looper);
+        } else {
+            mEventHandler = null;
+            Log.e(TAG, "RemoteController() couldn't find main application thread");
+        }
+        mContext = ctxt;
+        mRcd = new RcDisplay();
+        mAudioManager = (AudioManager) ctxt.getSystemService(Context.AUDIO_SERVICE);
+    }
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param looper
+     * @param ctxt non-null {@link Context}
+     * @throws java.lang.IllegalArgumentException
+     */
+    public RemoteController(Looper looper, Context ctxt) throws IllegalArgumentException {
+        if (ctxt == null) {
+            throw new IllegalArgumentException("Invalid null Context");
+        }
+        mEventHandler = new EventHandler(this, looper);
+        mContext = ctxt;
+        mRcd = new RcDisplay();
+        mAudioManager = (AudioManager) ctxt.getSystemService(Context.AUDIO_SERVICE);
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     */
+    public static abstract class OnClientUpdateListener {
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param clearing
+         */
+        public void onClientReset(boolean clearing) { }
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param state
+         */
+        public void onClientPlaybackStateUpdate(int state) { }
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param state
+         * @param stateChangeTimeMs
+         * @param currentPosMs
+         * @param speed
+         */
+        public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) { }
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param transportControlFlags
+         * @param posCapabilities
+         */
+        public void onClientTransportControlUpdate(int transportControlFlags) { }
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param metadataEditor
+         */
+        public void onClientMetadataUpdate(MetadataEditor metadataEditor) { }
+    };
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param l
+     */
+    public void setOnClientUpdateListener(OnClientUpdateListener l) {
+        synchronized(mInfoLock) {
+            mOnClientUpdateListener = l;
+            if (!mIsRegistered) {
+                // since the object is not registered, it hasn't received any information from
+                // RemoteControlClients yet, so we can exit here.
+                return;
+            }
+            if (mLastPlaybackInfo != null) {
+                sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
+                        mClientGenerationIdCurrent /*arg1*/, 0,
+                        mLastPlaybackInfo /*obj*/, 0 /*delay*/);
+            }
+            if (mLastTransportControlFlags != TRANSPORT_UNKNOWN) {
+                sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
+                        mClientGenerationIdCurrent /*arg1*/, mLastTransportControlFlags /*arg2*/,
+                        null /*obj*/, 0 /*delay*/);
+            }
+            if (mMetadataEditor != null) {
+                sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                        mClientGenerationIdCurrent /*arg1*/, 0 /*arg2*/,
+                        mMetadataEditor /*obj*/, 0 /*delay*/);
+            }
+        }
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Send a simulated key event for a media button.
+     * May be used without registering the RemoteController
+     * with {@link AudioManager#registerRemoteController(RemoteController)}. To simulate a key
+     * press, you must first send a KeyEvent built with a {@link KeyEvent#ACTION_DOWN} action, then
+     * another event with the {@link KeyEvent#ACTION_UP} action.
+     * <p> When used from a registered RemoteController, the key event will be sent to the
+     * application currently promoted to publish its media metadata and playback state (there may be
+     * none under some circumstances). With an unregistered RemoteController, the key event will be
+     * sent to the current media key event consumer
+     * (see {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}).
+     * @param keyEvent a {@link KeyEvent} instance whose key code is one of
+     *     {@link KeyEvent.KEYCODE_MUTE},
+     *     {@link KeyEvent.KEYCODE_HEADSETHOOK},
+     *     {@link KeyEvent.KEYCODE_MEDIA_PLAY},
+     *     {@link KeyEvent.KEYCODE_MEDIA_PAUSE},
+     *     {@link KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE},
+     *     {@link KeyEvent.KEYCODE_MEDIA_STOP},
+     *     {@link KeyEvent.KEYCODE_MEDIA_NEXT},
+     *     {@link KeyEvent.KEYCODE_MEDIA_PREVIOUS},
+     *     {@link KeyEvent.KEYCODE_MEDIA_REWIND},
+     *     {@link KeyEvent.KEYCODE_MEDIA_RECORD},
+     *     {@link KeyEvent.KEYCODE_MEDIA_FAST_FORWARD},
+     *     {@link KeyEvent.KEYCODE_MEDIA_CLOSE},
+     *     {@link KeyEvent.KEYCODE_MEDIA_EJECT},
+     *     or {@link KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK}.
+     */
+    public int sendMediaKeyEvent(KeyEvent keyEvent) {
+        if (!MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode())) {
+            Log.e(TAG, "Cannot use sendMediaKeyEvent() for a non-media key event");
+            return ERROR_BAD_VALUE;
+        }
+        boolean registered = false;
+        final PendingIntent pi;
+        synchronized(mInfoLock) {
+            registered = mIsRegistered;
+            pi = mClientPendingIntentCurrent;
+        }
+        if (registered) {
+            if (pi != null) {
+                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                try {
+                    pi.send(mContext, 0, intent);
+                } catch (CanceledException e) {
+                    Log.e(TAG, "Error sending intent for media button down: ", e);
+                    return ERROR;
+                }
+            } else {
+                Log.i(TAG, "No-op when sending key click, no receiver right now");
+                return ERROR;
+            }
+        } else {
+            mAudioManager.dispatchMediaKeyEvent(keyEvent);
+        }
+        return SUCCESS;
+    }
+
+
+    // Error codes
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Successful operation.
+     */
+    public  static final int SUCCESS            = 0;
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Unspecified error.
+     */
+    public  static final int ERROR              = -1;
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Operation failed due to bad parameter value.
+     */
+    public  static final int ERROR_BAD_VALUE    = -2;
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param timeMs
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int seekTo(long timeMs) {
+        if (timeMs < 0) {
+            return ERROR_BAD_VALUE;
+        }
+        final int genId;
+        synchronized (mGenLock) {
+            genId = mClientGenerationIdCurrent;
+        }
+        mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
+        return SUCCESS;
+    }
+
+
+    /**
+     * @hide
+     * must be called on a registered RemoteController
+     * @param wantBitmap
+     * @param width
+     * @param height
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int setBitmapConfiguration(boolean wantBitmap, int width, int height) {
+        synchronized (mInfoLock) {
+            if (!mIsRegistered) {
+                Log.e(TAG, "Cannot specify bitmap configuration on unregistered RemoteController");
+                return ERROR;
+            }
+        }
+        if (wantBitmap) {
+            if ((width > 0) && (height > 0)) {
+                if (width > MAX_BITMAP_DIMENSION) { width = MAX_BITMAP_DIMENSION; }
+                if (height > MAX_BITMAP_DIMENSION) { height = MAX_BITMAP_DIMENSION; }
+                mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd, width, height);
+            } else {
+                Log.e(TAG, "Invalid dimensions");
+                return ERROR_BAD_VALUE;
+            }
+        } else {
+            mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd, -1, -1);
+        }
+        return SUCCESS;
+    }
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * must be called on a registered RemoteController
+     * @param width
+     * @param height
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int setBitmapConfiguration(int width, int height) {
+        return setBitmapConfiguration(true, width, height);
+    }
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * must be called on a registered RemoteController
+     * @return {@link #SUCCESS}, {@link #ERROR}
+     */
+    public int setBitmapConfigurationNone() {
+        return setBitmapConfiguration(false, -1, -1);
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Default playback position synchronization mode where the RemoteControlClient is not
+     * asked regularly for its playback position to see if it has drifted from the estimated
+     * position.
+     */
+    public static final int POSITION_SYNCHRONIZATION_NONE = 0;
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * The playback position synchronization mode where the RemoteControlClient instances which
+     * expose their playback position to the framework, will be regularly polled to check
+     * whether any drift has been noticed between their estimated position and the one they report.
+     * Note that this mode should only ever be used when needing to display very accurate playback
+     * position, as regularly polling a RemoteControlClient for its position may have an impact
+     * on battery life (if applicable) when this query will trigger network transactions in the
+     * case of remote playback.
+     */
+    public static final int POSITION_SYNCHRONIZATION_CHECK = 1;
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Set the playback position synchronization mode.
+     * Must be called on a registered RemoteController.
+     * @param sync {@link #POSITION_SYNCHRONIZATION_NONE} or {@link #POSITION_SYNCHRONIZATION_CHECK}
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int setSynchronizationMode(int sync) {
+        if ((sync != POSITION_SYNCHRONIZATION_NONE) || (sync != POSITION_SYNCHRONIZATION_CHECK)) {
+            Log.e(TAG, "Unknown synchronization mode");
+            return ERROR_BAD_VALUE;
+        }
+        if (!mIsRegistered) {
+            Log.e(TAG, "Cannot set synchronization mode on an unregistered RemoteController");
+            return ERROR;
+        }
+        mAudioManager.remoteControlDisplayWantsPlaybackPositionSync(mRcd,
+                POSITION_SYNCHRONIZATION_CHECK == sync);
+        return SUCCESS;
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Creates a {@link MetadataEditor} for updating metadata values of the editable keys of
+     * the current {@link RemoteControlClient}.
+     * @return a new MetadataEditor instance.
+     */
+    public MetadataEditor editMetadata() {
+        MetadataEditor editor = new MetadataEditor();
+        editor.mEditorMetadata = new Bundle();
+        editor.mEditorArtwork = null;
+        editor.mMetadataChanged = true;
+        editor.mArtworkChanged = true;
+        editor.mEditableKeys = 0;
+        return editor;
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Used to read the metadata published by a {@link RemoteControlClient}, or send a
+     * {@link RemoteControlClient} new values for keys that can be edited.
+     */
+    public class MetadataEditor extends MediaMetadataEditor {
+        /**
+         * @hide
+         */
+        protected MetadataEditor() { }
+
+        /**
+         * @hide
+         */
+        protected MetadataEditor(Bundle metadata, long editableKeys) {
+            mEditorMetadata = metadata;
+            mEditableKeys = editableKeys;
+            mEditorArtwork = null;
+            mMetadataChanged = true;
+            mArtworkChanged = true;
+            mApplied = false;
+        }
+
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         */
+        public synchronized void apply() {
+            // "applying" a metadata bundle in RemoteController is only for sending edited
+            // key values back to the RemoteControlClient, so here we only care about the only
+            // editable key we support: RATING_KEY_BY_USER
+            if (!mMetadataChanged) {
+                return;
+            }
+            final int genId;
+            synchronized(mGenLock) {
+                genId = mClientGenerationIdCurrent;
+            }
+            synchronized(mInfoLock) {
+                if (mEditorMetadata.containsKey(
+                        String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
+                    Rating rating = (Rating) getObject(
+                            MediaMetadataEditor.RATING_KEY_BY_USER, null);
+                    mAudioManager.updateRemoteControlClientMetadata(genId,
+                          MediaMetadataEditor.RATING_KEY_BY_USER,
+                          rating);
+                } else {
+                    Log.e(TAG, "no metadata to apply");
+                }
+                // NOT setting mApplied to true as this type of MetadataEditor will be applied
+                // multiple times, whenever the user of a RemoteController needs to change the
+                // metadata (e.g. user changes the rating of a song more than once during playback)
+                mApplied = false;
+            }
+        }
+
+    }
+
+
+    //==================================================
+    // Implementation of IRemoteControlDisplay interface
+    private class RcDisplay extends IRemoteControlDisplay.Stub {
+        /**
+         * @hide
+         */
+        public void setCurrentClientId(int genId, PendingIntent clientMediaIntent,
+                boolean clearing) {
+            boolean isNew = false;
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    mClientGenerationIdCurrent = genId;
+                    isNew = true;
+                }
+            }
+            if (clientMediaIntent != null) {
+                sendMsg(mEventHandler, MSG_NEW_PENDING_INTENT, SENDMSG_REPLACE,
+                        genId /*arg1*/, 0, clientMediaIntent /*obj*/, 0 /*delay*/);
+            }
+            if (isNew || clearing) {
+                sendMsg(mEventHandler, MSG_CLIENT_RESET, SENDMSG_REPLACE,
+                        genId /*arg1*/, clearing ? 1 : 0, null /*obj*/, 0 /*delay*/);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public void setPlaybackState(int genId, int state,
+                long stateChangeTimeMs, long currentPosMs, float speed) {
+            if (DEBUG) {
+                Log.d(TAG, "> new playback state: genId="+genId
+                        + " state="+ state
+                        + " changeTime="+ stateChangeTimeMs
+                        + " pos=" + currentPosMs
+                        + "ms speed=" + speed);
+            }
+
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            final PlaybackInfo playbackInfo =
+                    new PlaybackInfo(state, stateChangeTimeMs, currentPosMs, speed);
+            sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
+                    genId /*arg1*/, 0, playbackInfo /*obj*/, 0 /*delay*/);
+
+        }
+
+        /**
+         * @hide
+         */
+        public void setTransportControlInfo(int genId, int transportControlFlags,
+                int posCapabilities) {
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
+                    genId /*arg1*/, transportControlFlags /*arg2*/,
+                    null /*obj*/, 0 /*delay*/);
+        }
+
+        /**
+         * @hide
+         */
+        public void setMetadata(int genId, Bundle metadata) {
+            if (DEBUG) { Log.e(TAG, "setMetadata("+genId+")"); }
+            if (metadata == null) {
+                return;
+            }
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                    genId /*arg1*/, 0 /*arg2*/,
+                    metadata /*obj*/, 0 /*delay*/);
+        }
+
+        /**
+         * @hide
+         */
+        public void setArtwork(int genId, Bitmap artwork) {
+            if (DEBUG) { Log.v(TAG, "setArtwork("+genId+")"); }
+            if (artwork == null) {
+                return;
+            }
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            Bundle metadata = new Bundle(1);
+            metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), artwork);
+            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                    genId /*arg1*/, 0 /*arg2*/,
+                    metadata /*obj*/, 0 /*delay*/);
+        }
+
+        /**
+         * @hide
+         */
+        public void setAllMetadata(int genId, Bundle metadata, Bitmap artwork) {
+            if (DEBUG) { Log.e(TAG, "setAllMetadata("+genId+")"); }
+            if ((metadata == null) && (artwork == null)) {
+                return;
+            }
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            if (metadata == null) {
+                metadata = new Bundle(1);
+            }
+            if (artwork != null) {
+                metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+                        artwork);
+            }
+            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                    genId /*arg1*/, 0 /*arg2*/,
+                    metadata /*obj*/, 0 /*delay*/);
+        }
+    }
+
+    //==================================================
+    // Event handling
+    private EventHandler mEventHandler;
+    private final static int MSG_NEW_PENDING_INTENT = 0;
+    private final static int MSG_NEW_PLAYBACK_INFO =  1;
+    private final static int MSG_NEW_TRANSPORT_INFO = 2;
+    private final static int MSG_NEW_METADATA       = 3; // msg always has non-null obj parameter
+    private final static int MSG_CLIENT_RESET       = 4;
+
+    private class EventHandler extends Handler {
+
+        public EventHandler(RemoteController rc, Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_NEW_PENDING_INTENT:
+                    onNewPendingIntent(msg.arg1, (PendingIntent) msg.obj);
+                    break;
+                case MSG_NEW_PLAYBACK_INFO:
+                    onNewPlaybackInfo(msg.arg1, (PlaybackInfo) msg.obj);
+                    break;
+                case MSG_NEW_TRANSPORT_INFO:
+                    onNewTransportInfo(msg.arg1, msg.arg2);
+                    break;
+                case MSG_NEW_METADATA:
+                    onNewMetadata(msg.arg1, (Bundle)msg.obj);
+                    break;
+                case MSG_CLIENT_RESET:
+                    onClientReset(msg.arg1, msg.arg2 == 1);
+                    break;
+                default:
+                    Log.e(TAG, "unknown event " + msg.what);
+            }
+        }
+    }
+
+    /** If the msg is already queued, replace it with this one. */
+    private static final int SENDMSG_REPLACE = 0;
+    /** If the msg is already queued, ignore this one and leave the old. */
+    private static final int SENDMSG_NOOP = 1;
+    /** If the msg is already queued, queue this one and leave the old. */
+    private static final int SENDMSG_QUEUE = 2;
+
+    private static void sendMsg(Handler handler, int msg, int existingMsgPolicy,
+            int arg1, int arg2, Object obj, int delayMs) {
+        if (handler == null) {
+            Log.e(TAG, "null event handler, will not deliver message " + msg);
+            return;
+        }
+        if (existingMsgPolicy == SENDMSG_REPLACE) {
+            handler.removeMessages(msg);
+        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+            return;
+        }
+        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delayMs);
+    }
+
+    private void onNewPendingIntent(int genId, PendingIntent pi) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        synchronized(mInfoLock) {
+            mClientPendingIntentCurrent = pi;
+        }
+    }
+
+    private void onNewPlaybackInfo(int genId, PlaybackInfo pi) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        synchronized(mInfoLock) {
+            l = this.mOnClientUpdateListener;
+            mLastPlaybackInfo = pi;
+        }
+        if (l != null) {
+            if (pi.mCurrentPosMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
+                l.onClientPlaybackStateUpdate(pi.mState);
+            } else {
+                l.onClientPlaybackStateUpdate(pi.mState, pi.mStateChangeTimeMs, pi.mCurrentPosMs,
+                        pi.mSpeed);
+            }
+        }
+    }
+
+    private void onNewTransportInfo(int genId, int transportControlFlags) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+            mLastTransportControlFlags = transportControlFlags;
+        }
+        if (l != null) {
+            l.onClientTransportControlUpdate(transportControlFlags);
+        }
+    }
+
+    /**
+     * @param genId
+     * @param metadata guaranteed to be always non-null
+     */
+    private void onNewMetadata(int genId, Bundle metadata) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        final MetadataEditor metadataEditor;
+        // prepare the received Bundle to be used inside a MetadataEditor
+        final long editableKeys = metadata.getLong(
+                String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK), 0);
+        if (editableKeys != 0) {
+            metadata.remove(String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK));
+        }
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+            if ((mMetadataEditor != null) && (mMetadataEditor.mEditorMetadata != null)) {
+                if (mMetadataEditor.mEditorMetadata != metadata) {
+                    // existing metadata, merge existing and new
+                    mMetadataEditor.mEditorMetadata.putAll(metadata);
+                }
+            } else {
+                mMetadataEditor = new MetadataEditor(metadata, editableKeys);
+            }
+            metadataEditor = mMetadataEditor;
+        }
+        if (l != null) {
+            l.onClientMetadataUpdate(metadataEditor);
+        }
+    }
+
+    private void onClientReset(int genId, boolean clearing) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+        }
+        if (l != null) {
+            l.onClientReset(clearing);
+        }
+    }
+
+
+    //==================================================
+    private static class PlaybackInfo {
+        int mState;
+        long mStateChangeTimeMs;
+        long mCurrentPosMs;
+        float mSpeed;
+
+        PlaybackInfo(int state, long stateChangeTimeMs, long currentPosMs, float speed) {
+            mState = state;
+            mStateChangeTimeMs = stateChangeTimeMs;
+            mCurrentPosMs = currentPosMs;
+            mSpeed = speed;
+        }
+    }
+
+    /**
+     * @hide
+     * Used by AudioManager to mark this instance as registered.
+     * @param registered
+     */
+    protected void setIsRegistered(boolean registered) {
+        synchronized (mInfoLock) {
+            mIsRegistered = registered;
+        }
+    }
+
+    /**
+     * @hide
+     * Used by AudioManager to access binder to be registered/unregistered inside MediaFocusControl
+     * @return
+     */
+    protected RcDisplay getRcDisplay() {
+        return mRcd;
+    }
+}
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
index e83c5ba..8090561 100644
--- a/media/java/android/media/SubtitleController.java
+++ b/media/java/android/media/SubtitleController.java
@@ -38,6 +38,21 @@
     private boolean mShowing;
     private CaptioningManager mCaptioningManager;
 
+    private CaptioningManager.CaptioningChangeListener mCaptioningChangeListener =
+        new CaptioningManager.CaptioningChangeListener() {
+            /** @hide */
+            @Override
+            public void onEnabledChanged(boolean enabled) {
+                selectDefaultTrack();
+            }
+
+            /** @hide */
+            @Override
+            public void onLocaleChanged(Locale locale) {
+                selectDefaultTrack();
+            }
+        };
+
     /**
      * Creates a subtitle controller for a media playback object that implements
      * the MediaTimeProvider interface.
@@ -58,15 +73,24 @@
             (CaptioningManager)context.getSystemService(Context.CAPTIONING_SERVICE);
     }
 
+    @Override
+    protected void finalize() throws Throwable {
+        mCaptioningManager.removeCaptioningChangeListener(
+                mCaptioningChangeListener);
+        super.finalize();
+    }
+
     /**
      * @return the available subtitle tracks for this media. These include
      * the tracks found by {@link MediaPlayer} as well as any tracks added
      * manually via {@link #addTrack}.
      */
     public SubtitleTrack[] getTracks() {
-        SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
-        mTracks.toArray(tracks);
-        return tracks;
+        synchronized(mTracks) {
+            SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
+            mTracks.toArray(tracks);
+            return tracks;
+        }
     }
 
     /**
@@ -88,6 +112,8 @@
      * in-band data from the {@link MediaPlayer}.  However, this does
      * not change the subtitle visibility.
      *
+     * Must be called from the UI thread.
+     *
      * @param track The subtitle track to select.  This must be one of the
      *              tracks in {@link #getTracks}.
      * @return true if the track was successfully selected.
@@ -107,7 +133,9 @@
         }
 
         mSelectedTrack = track;
-        mAnchor.setSubtitleWidget(getRenderingWidget());
+        if (mAnchor != null) {
+            mAnchor.setSubtitleWidget(getRenderingWidget());
+        }
 
         if (mSelectedTrack != null) {
             mSelectedTrack.setTimeProvider(mTimeProvider);
@@ -123,56 +151,123 @@
     /**
      * @return the default subtitle track based on system preferences, or null,
      * if no such track exists in this manager.
+     *
+     * Supports HLS-flags: AUTOSELECT, FORCED & DEFAULT.
+     *
+     * 1. If captioning is disabled, only consider FORCED tracks. Otherwise,
+     * consider all tracks, but prefer non-FORCED ones.
+     * 2. If user selected "Default" caption language:
+     *   a. If there is a considered track with DEFAULT=yes, returns that track
+     *      (favor the first one in the current language if there are more than
+     *      one default tracks, or the first in general if none of them are in
+     *      the current language).
+     *   b. Otherwise, if there is a track with AUTOSELECT=yes in the current
+     *      language, return that one.
+     *   c. If there are no default tracks, and no autoselectable tracks in the
+     *      current language, return null.
+     * 3. If there is a track with the caption language, select that one.  Prefer
+     * the one with AUTOSELECT=no.
+     *
+     * The default values for these flags are DEFAULT=no, AUTOSELECT=yes
+     * and FORCED=no.
+     *
+     * Must be called from the UI thread.
      */
     public SubtitleTrack getDefaultTrack() {
-        Locale locale = mCaptioningManager.getLocale();
+        SubtitleTrack bestTrack = null;
+        int bestScore = -1;
 
-        for (SubtitleTrack track: mTracks) {
-            MediaFormat format = track.getFormat();
-            String language = format.getString(MediaFormat.KEY_LANGUAGE);
-            // TODO: select track with best renderer.  For now, we select first
-            // track with local's language or first track if locale has none
-            if (locale == null ||
-                locale.getLanguage().equals("") ||
-                locale.getISO3Language().equals(language) ||
-                locale.getLanguage().equals(language)) {
-                return track;
+        Locale selectedLocale = mCaptioningManager.getLocale();
+        Locale locale = selectedLocale;
+        if (locale == null) {
+            locale = Locale.getDefault();
+        }
+        boolean selectForced = !mCaptioningManager.isEnabled();
+
+        synchronized(mTracks) {
+            for (SubtitleTrack track: mTracks) {
+                MediaFormat format = track.getFormat();
+                String language = format.getString(MediaFormat.KEY_LANGUAGE);
+                boolean forced =
+                    format.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0;
+                boolean autoselect =
+                    format.getInteger(MediaFormat.KEY_IS_AUTOSELECT, 1) != 0;
+                boolean is_default =
+                    format.getInteger(MediaFormat.KEY_IS_DEFAULT, 0) != 0;
+
+                boolean languageMatches =
+                    (locale == null ||
+                    locale.getLanguage().equals("") ||
+                    locale.getISO3Language().equals(language) ||
+                    locale.getLanguage().equals(language));
+                // is_default is meaningless unless caption language is 'default'
+                int score = (forced ? 0 : 8) +
+                    (((selectedLocale == null) && is_default) ? 4 : 0) +
+                    (autoselect ? 0 : 2) + (languageMatches ? 1 : 0);
+
+                if (selectForced && !forced) {
+                    continue;
+                }
+
+                // we treat null locale/language as matching any language
+                if ((selectedLocale == null && is_default) ||
+                    (languageMatches &&
+                     (autoselect || forced || selectedLocale != null))) {
+                    if (score > bestScore) {
+                        bestScore = score;
+                        bestTrack = track;
+                    }
+                }
             }
         }
-        return null;
+        return bestTrack;
     }
 
     private boolean mTrackIsExplicit = false;
     private boolean mVisibilityIsExplicit = false;
 
-    /** @hide */
+    /** @hide - called from UI thread */
     public void selectDefaultTrack() {
         if (mTrackIsExplicit) {
-            return;
-        }
-
-        SubtitleTrack track = getDefaultTrack();
-        if (track != null) {
-            selectTrack(track);
-            mTrackIsExplicit = false;
+            // If track selection is explicit, but visibility
+            // is not, it falls back to the captioning setting
             if (!mVisibilityIsExplicit) {
-                if (mCaptioningManager.isEnabled()) {
+                if (mCaptioningManager.isEnabled() ||
+                    (mSelectedTrack != null &&
+                     mSelectedTrack.getFormat().getInteger(
+                            MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
                     show();
                 } else {
                     hide();
                 }
                 mVisibilityIsExplicit = false;
             }
+            return;
+        }
+
+        // We can have a default (forced) track even if captioning
+        // is not enabled.  This is handled by getDefaultTrack().
+        // Show this track unless subtitles were explicitly hidden.
+        SubtitleTrack track = getDefaultTrack();
+        if (track != null) {
+            selectTrack(track);
+            mTrackIsExplicit = false;
+            if (!mVisibilityIsExplicit) {
+                show();
+                mVisibilityIsExplicit = false;
+            }
         }
     }
 
-    /** @hide */
+    /** @hide - called from UI thread */
     public void reset() {
         hide();
         selectTrack(null);
         mTracks.clear();
         mTrackIsExplicit = false;
         mVisibilityIsExplicit = false;
+        mCaptioningManager.removeCaptioningChangeListener(
+                mCaptioningChangeListener);
     }
 
     /**
@@ -183,12 +278,20 @@
      * @return the created {@link SubtitleTrack} object
      */
     public SubtitleTrack addTrack(MediaFormat format) {
-        for (Renderer renderer: mRenderers) {
-            if (renderer.supports(format)) {
-                SubtitleTrack track = renderer.createTrack(format);
-                if (track != null) {
-                    mTracks.add(track);
-                    return track;
+        synchronized(mRenderers) {
+            for (Renderer renderer: mRenderers) {
+                if (renderer.supports(format)) {
+                    SubtitleTrack track = renderer.createTrack(format);
+                    if (track != null) {
+                        synchronized(mTracks) {
+                            if (mTracks.size() == 0) {
+                                mCaptioningManager.addCaptioningChangeListener(
+                                        mCaptioningChangeListener);
+                            }
+                            mTracks.add(track);
+                        }
+                        return track;
+                    }
                 }
             }
         }
@@ -197,6 +300,8 @@
 
     /**
      * Show the selected (or default) subtitle track.
+     *
+     * Must be called from the UI thread.
      */
     public void show() {
         mShowing = true;
@@ -208,6 +313,8 @@
 
     /**
      * Hide the selected (or default) subtitle track.
+     *
+     * Must be called from the UI thread.
      */
     public void hide() {
         mVisibilityIsExplicit = true;
@@ -257,10 +364,12 @@
      *                 support for a subtitle format.
      */
     public void registerRenderer(Renderer renderer) {
-        // TODO how to get available renderers in the system
-        if (!mRenderers.contains(renderer)) {
-            // TODO should added renderers override existing ones (to allow replacing?)
-            mRenderers.add(renderer);
+        synchronized(mRenderers) {
+            // TODO how to get available renderers in the system
+            if (!mRenderers.contains(renderer)) {
+                // TODO should added renderers override existing ones (to allow replacing?)
+                mRenderers.add(renderer);
+            }
         }
     }
 
@@ -279,7 +388,7 @@
 
     private Anchor mAnchor;
 
-    /** @hide */
+    /** @hide - called from UI thread */
     public void setAnchor(Anchor anchor) {
         if (mAnchor == anchor) {
             return;
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index cb689af..06063de 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -69,7 +69,7 @@
     }
 
     /** @hide */
-    public MediaFormat getFormat() {
+    public final MediaFormat getFormat() {
         return mFormat;
     }
 
@@ -201,7 +201,7 @@
     }
 
     /** @hide */
-    public void scheduleTimedEvents() {
+    protected void scheduleTimedEvents() {
         /* get times for the next event */
         if (mTimeProvider != null) {
             mNextScheduledTimeMs = mCues.nextTimeAfter(mLastTimeMs);
@@ -363,7 +363,7 @@
     }
 
     /** @hide */
-    public void setTimeProvider(MediaTimeProvider timeProvider) {
+    public synchronized void setTimeProvider(MediaTimeProvider timeProvider) {
         if (mTimeProvider == timeProvider) {
             return;
         }
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 16b45be..0030dbd 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,37 +703,37 @@
     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;
+    }
+
+    if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+        jniThrowException(env, "java/lang/UnsupportedOperationException",
+                "NV21 format is not supported by ImageReader");
+        return -1;
     }
 
     // Check if the left-top corner of the crop rect is origin, we currently assume this point is
     // zero, will revist this once this assumption turns out problematic.
     Point lt = buffer->crop.leftTop();
     if (lt.x != 0 || lt.y != 0) {
-        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;
+        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+                "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
+        return -1;
     }
 
     // Check if the producer buffer configurations match what ImageReader configured.
@@ -739,7 +742,7 @@
     int outputHeight = buffer->height;
 
     // Correct width/height when crop is set.
-    if (buffer->crop.isValid()) {
+    if (!buffer->crop.isEmpty()) {
         outputWidth = buffer->crop.getWidth();
         outputHeight = buffer->crop.getHeight();
     }
@@ -759,6 +762,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) {
@@ -775,14 +779,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)
@@ -853,7 +857,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/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-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-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/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-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-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-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 e690fa4..412a84b 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -38,8 +38,7 @@
     <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/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-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-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 8c662cc..297312c 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/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-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 2076934..1de881d 100644
--- a/packages/ExternalStorageProvider/res/values-af/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-af/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"Dokumente"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-ar/strings.xml b/packages/ExternalStorageProvider/res/values-ar/strings.xml
index 9c4b496..b20a056 100644
--- a/packages/ExternalStorageProvider/res/values-ar/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-ar/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"مستندات"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-da/strings.xml b/packages/ExternalStorageProvider/res/values-da/strings.xml
index 2ced56e..a9ecb69 100644
--- a/packages/ExternalStorageProvider/res/values-da/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-da/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 8d8e3a6..318634a 100644
--- a/packages/ExternalStorageProvider/res/values-de/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-de/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 9720b3d..b3aa792 100644
--- a/packages/ExternalStorageProvider/res/values-el/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-el/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"Έγγραφα"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-es/strings.xml b/packages/ExternalStorageProvider/res/values-es/strings.xml
index 7285a34..e7e38b5 100644
--- a/packages/ExternalStorageProvider/res/values-es/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-es/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 19357cc..6824e9d 100644
--- a/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-et-rEE/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 f61e5cb..8471fc7 100644
--- a/packages/ExternalStorageProvider/res/values-fa/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fa/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 a674b49..9d1fbaa 100644
--- a/packages/ExternalStorageProvider/res/values-fi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fi/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"Dokumentit"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-fr/strings.xml b/packages/ExternalStorageProvider/res/values-fr/strings.xml
index 294bd69..b3fdd48 100644
--- a/packages/ExternalStorageProvider/res/values-fr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-fr/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 72b4788..1227bd4 100644
--- a/packages/ExternalStorageProvider/res/values-hi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hi/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 c2d049e..a74f8e8 100644
--- a/packages/ExternalStorageProvider/res/values-hr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hr/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 bc581e2..3f72b41 100644
--- a/packages/ExternalStorageProvider/res/values-hu/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-hu/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"Dokumentumok"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-it/strings.xml b/packages/ExternalStorageProvider/res/values-it/strings.xml
index c1bd54c..957b5ff 100644
--- a/packages/ExternalStorageProvider/res/values-it/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-it/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 ca3da87..775506a 100644
--- a/packages/ExternalStorageProvider/res/values-iw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-iw/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"מסמכים"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
index 77ba762..9cf76d4 100644
--- a/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-km-rKH/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 d6842b5..240ea89 100644
--- a/packages/ExternalStorageProvider/res/values-lt/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lt/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 c906087..d308fe8 100644
--- a/packages/ExternalStorageProvider/res/values-lv/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-lv/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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
index 8319af8..3d7b7f7 100644
--- a/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-mn-rMN/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"Документүүд"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-nb/strings.xml b/packages/ExternalStorageProvider/res/values-nb/strings.xml
index 2ced56e..a9ecb69 100644
--- a/packages/ExternalStorageProvider/res/values-nb/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nb/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 843679f..bde6166 100644
--- a/packages/ExternalStorageProvider/res/values-nl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-nl/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 a166793..6c5e7d7 100644
--- a/packages/ExternalStorageProvider/res/values-pl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pl/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 eec824f..77c89b8 100644
--- a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
@@ -18,6 +18,5 @@
     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 />
+    <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-sl/strings.xml b/packages/ExternalStorageProvider/res/values-sl/strings.xml
index 5f7ddd2..6ffa698 100644
--- a/packages/ExternalStorageProvider/res/values-sl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sl/strings.xml
@@ -18,6 +18,5 @@
     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">"Notranja shramba"</string>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 987f848..54238a4 100644
--- a/packages/ExternalStorageProvider/res/values-sr/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sr/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"Документи"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-sw/strings.xml b/packages/ExternalStorageProvider/res/values-sw/strings.xml
index 0495a31..0d0e483 100644
--- a/packages/ExternalStorageProvider/res/values-sw/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sw/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 3a24f7d..796635e 100644
--- a/packages/ExternalStorageProvider/res/values-th/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-th/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 2687129..529cdc2 100644
--- a/packages/ExternalStorageProvider/res/values-tl/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-tl/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"Mga Dokumento"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-uk/strings.xml b/packages/ExternalStorageProvider/res/values-uk/strings.xml
index d993be8..b8206e0 100644
--- a/packages/ExternalStorageProvider/res/values-uk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-uk/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 7713ade..b171c93 100644
--- a/packages/ExternalStorageProvider/res/values-vi/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-vi/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"Tài liệu"</string>
 </resources>
diff --git a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
index df52d38..62d8afb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rHK/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <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 df52d38..62d8afb 100644
--- a/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-zh-rTW/strings.xml
@@ -18,6 +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>
-    <!-- no translation found for root_documents (4051252304075469250) -->
-    <skip />
+    <string name="root_documents" msgid="4051252304075469250">"文件"</string>
 </resources>
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 7d77c48..c05d527 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -37,6 +37,7 @@
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
     <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+    <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
 
     <application android:label="@string/app_name"
         android:process="com.android.systemui"
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 6badaaf..8cdcb7a 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -102,6 +102,8 @@
                 == TelephonyManager.CALL_STATE_OFFHOOK) {
             mLockPatternUtils.resumeCall();
         } else {
+            final boolean bypassHandler = true;
+            KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(bypassHandler);
             Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
index 3e499b2..c2cd32f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
@@ -295,6 +295,13 @@
                 }
             }
         }
+
+        @Override
+        public void onEmergencyCallAction() {
+            if (mBiometricUnlock != null) {
+                mBiometricUnlock.stop();
+            }
+        }
     };
 
     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index dcec654..f4bbf9a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -91,6 +91,7 @@
     private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
     protected static final int MSG_SET_PLAYBACK_STATE = 316;
     protected static final int MSG_USER_INFO_CHANGED = 317;
+    protected static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
 
 
     private static KeyguardUpdateMonitor sInstance;
@@ -181,6 +182,9 @@
                 case MSG_USER_INFO_CHANGED:
                     handleUserInfoChanged(msg.arg1);
                     break;
+                case MSG_REPORT_EMERGENCY_CALL_ACTION:
+                    handleReportEmergencyCallAction();
+                    break;
             }
         }
     };
@@ -758,6 +762,18 @@
         }
     }
 
+    /**
+     * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
+     */
+    private void handleReportEmergencyCallAction() {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onEmergencyCallAction();
+            }
+        }
+    }
+
     public boolean isKeyguardVisible() {
         return mKeyguardIsVisible;
     }
@@ -902,6 +918,22 @@
         handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
     }
 
+    /**
+     * Report that the emergency call button has been pressed and the emergency dialer is
+     * about to be displayed.
+     *
+     * @param bypassHandler runs immediately.
+     *
+     * NOTE: Must be called from UI thread if bypassHandler == true.
+     */
+    public void reportEmergencyCallAction(boolean bypassHandler) {
+        if (!bypassHandler) {
+            mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget();
+        } else {
+            handleReportEmergencyCallAction();
+        }
+    }
+
     public CharSequence getTelephonyPlmn() {
         return mTelephonyPlmn;
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 30b43f5..b0511e5 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -131,4 +131,8 @@
      */
     public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { }
 
+    /**
+     * Called when the emergency call button is pressed.
+     */
+    void onEmergencyCallAction() { }
 }
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 9319025..1e6954e 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -44,7 +44,7 @@
     <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 21a4867..543c425 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -139,18 +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">start print service configuration activities</string>
+    <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">Allows the holder to start the
-        configuration activities of a print service. Should never be needed for normal apps.</string>
+    <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 14f60f1..8ab4645 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;
@@ -104,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";
 
@@ -163,7 +163,7 @@
     private Document mDocument;
     private PrintController mController;
 
-    private int mPrintJobId;
+    private PrintJobId mPrintJobId;
 
     private IBinder mIPrintDocumentAdapter;
 
@@ -175,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);
         }
@@ -413,12 +414,25 @@
             // write anything and wait for the user to fix the range which will
             // trigger an update.
             mRequestedPages = mEditor.getRequestedPages();
-            if (mRequestedPages == null) {
+            if (mRequestedPages == null || mRequestedPages.length == 0) {
                 mEditor.updateUi();
                 if (mEditor.isDone()) {
                     PrintJobConfigActivity.this.finish();
                 }
                 return;
+            } else {
+                // If print is not confirmed we just ask for the first of the
+                // selected pages to emulate a behavior that shows preview
+                // increasing the chances that apps will implement the APIs
+                // correctly.
+                if (!mEditor.isPrintConfirmed()) {
+                    if (ALL_PAGES_ARRAY.equals(mRequestedPages)) {
+                        mRequestedPages = new PageRange[] {new PageRange(0, 0)};
+                    } else {
+                        final int firstPage = mRequestedPages[0].getStart();
+                        mRequestedPages = new PageRange[] {new PageRange(firstPage, firstPage)};
+                    }
+                }
             }
 
             // If the info and the layout did not change and we already have
@@ -1460,8 +1474,12 @@
 
                     if (dashIndex > 0) {
                         fromIndex = Integer.parseInt(range.substring(0, dashIndex)) - 1;
-                        toIndex = Integer.parseInt(range.substring(
-                                dashIndex + 1, range.length())) - 1;
+                        // It is possible that the dash is at the end since the input
+                        // verification can has to allow the user to keep entering if
+                        // this would lead to a valid input. So we handle this.
+                        toIndex = (dashIndex < range.length() - 1)
+                                ? Integer.parseInt(range.substring(dashIndex + 1,
+                                        range.length())) - 1 : fromIndex;
                     } else {
                         fromIndex = toIndex = Integer.parseInt(range) - 1;
                     }
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/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 1d0d99d..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>
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/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/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
rename to packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
index f17766b..1cfc892 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
@@ -30,7 +30,7 @@
 
 import com.android.systemui.R;
 
-public class RecentsScrollViewPerformanceHelper {
+public class FadedEdgeDrawHelper {
     public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
     public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
     private View mScrollView;
@@ -43,18 +43,18 @@
     private Matrix mFadeMatrix;
     private LinearGradient mFade;
 
-    public static RecentsScrollViewPerformanceHelper create(Context context,
+    public static FadedEdgeDrawHelper create(Context context,
             AttributeSet attrs, View scrollView, boolean isVertical) {
         boolean isTablet = context.getResources().
                 getBoolean(R.bool.config_recents_interface_for_tablets);
         if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
-            return new RecentsScrollViewPerformanceHelper(context, attrs, scrollView, isVertical);
+            return new FadedEdgeDrawHelper(context, attrs, scrollView, isVertical);
         } else {
             return null;
         }
     }
 
-    public RecentsScrollViewPerformanceHelper(Context context,
+    public FadedEdgeDrawHelper(Context context,
             AttributeSet attrs, View scrollView, boolean isVertical) {
         mScrollView = scrollView;
         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
@@ -64,7 +64,7 @@
     }
 
     public void onAttachedToWindowCallback(
-            RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) {
+            LinearLayout layout, boolean hardwareAccelerated) {
         mSoftwareRendered = !hardwareAccelerated;
         if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
                 || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
@@ -178,11 +178,11 @@
         }
     }
 
-    public int getVerticalFadingEdgeLengthCallback() {
+    public int getVerticalFadingEdgeLength() {
         return mFadingEdgeLength;
     }
 
-    public int getHorizontalFadingEdgeLengthCallback() {
+    public int getHorizontalFadingEdgeLength() {
         return mFadingEdgeLength;
     }
 
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/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 217b7fd..be42bc0 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -49,16 +49,17 @@
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
-    private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+    private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
     private HashSet<View> mRecycledViews;
     private int mNumItemsInOneScreenful;
+    private Runnable mOnScrollListener;
 
     public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
         float densityScale = getResources().getDisplayMetrics().density;
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
-        mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false);
+        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
         mRecycledViews = new HashSet<View>();
     }
 
@@ -108,8 +109,8 @@
 
             final View view = mAdapter.getView(i, old, mLinearLayout);
 
-            if (mPerformanceHelper != null) {
-                mPerformanceHelper.addViewCallback(view);
+            if (mFadedEdgeDrawHelper != null) {
+                mFadedEdgeDrawHelper.addViewCallback(view);
             }
 
             OnTouchListener noOpListener = new OnTouchListener() {
@@ -234,26 +235,10 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
+    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+        if (mFadedEdgeDrawHelper != null) {
 
-        if (mPerformanceHelper != null) {
-            int paddingLeft = mPaddingLeft;
-            final boolean offsetRequired = isPaddingOffsetRequired();
-            if (offsetRequired) {
-                paddingLeft += getLeftPaddingOffset();
-            }
-
-            int left = mScrollX + paddingLeft;
-            int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
-            int top = mScrollY + getFadeTop(offsetRequired);
-            int bottom = top + getFadeHeight(offsetRequired);
-
-            if (offsetRequired) {
-                right += getRightPaddingOffset();
-                bottom += getBottomPaddingOffset();
-            }
-            mPerformanceHelper.drawCallback(canvas,
+            mFadedEdgeDrawHelper.drawCallback(canvas,
                     left, right, top, bottom, mScrollX, mScrollY,
                     0, 0,
                     getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), mPaddingTop);
@@ -261,9 +246,21 @@
     }
 
     @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+       super.onScrollChanged(l, t, oldl, oldt);
+       if (mOnScrollListener != null) {
+           mOnScrollListener.run();
+       }
+    }
+
+    public void setOnScrollListener(Runnable listener) {
+        mOnScrollListener = listener;
+    }
+
+    @Override
     public int getVerticalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
         } else {
             return super.getVerticalFadingEdgeLength();
         }
@@ -271,8 +268,8 @@
 
     @Override
     public int getHorizontalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
         } else {
             return super.getHorizontalFadingEdgeLength();
         }
@@ -290,9 +287,8 @@
 
     @Override
     public void onAttachedToWindow() {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.onAttachedToWindowCallback(
-                    mCallback, mLinearLayout, isHardwareAccelerated());
+        if (mFadedEdgeDrawHelper != null) {
+            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 5ebd11e0..788e843 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Shader.TileMode;
 import android.graphics.drawable.BitmapDrawable;
@@ -74,7 +75,7 @@
     private PopupMenu mPopup;
     private View mRecentsScrim;
     private View mRecentsNoApps;
-    private ViewGroup mRecentsContainer;
+    private RecentsScrollView mRecentsContainer;
 
     private boolean mShowing;
     private boolean mWaitingToShow;
@@ -98,6 +99,8 @@
         public void setCallback(RecentsCallback callback);
         public void setMinSwipeAlpha(float minAlpha);
         public View findViewForTask(int persistentTaskId);
+        public void drawFadedEdges(Canvas c, int left, int right, int top, int bottom);
+        public void setOnScrollListener(Runnable listener);
     }
 
     private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -113,7 +116,7 @@
     /* package */ final static class ViewHolder {
         View thumbnailView;
         ImageView thumbnailViewImage;
-        Bitmap thumbnailViewImageBitmap;
+        Drawable thumbnailViewDrawable;
         ImageView iconView;
         TextView labelView;
         TextView descriptionView;
@@ -151,7 +154,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);
@@ -227,7 +230,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);
@@ -270,13 +273,7 @@
     }
 
     public int numItemsInOneScreenful() {
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                    = (RecentsScrollView) mRecentsContainer;
-            return scrollView.numItemsInOneScreenful();
-        }  else {
-            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
-        }
+        return mRecentsContainer.numItemsInOneScreenful();
     }
 
     private boolean pointInside(int x, int y, View v) {
@@ -288,7 +285,7 @@
     }
 
     public boolean isInContentArea(int x, int y) {
-        return pointInside(x, y, mRecentsContainer);
+        return pointInside(x, y, (View) mRecentsContainer);
     }
 
     public void show(boolean show) {
@@ -436,16 +433,16 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
+        mRecentsContainer = (RecentsScrollView) findViewById(R.id.recents_container);
+        mRecentsContainer.setOnScrollListener(new Runnable() {
+            public void run() {
+                // need to redraw the faded edges
+                invalidate();
+            }
+        });
         mListAdapter = new TaskDescriptionAdapter(mContext);
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                    = (RecentsScrollView) mRecentsContainer;
-            scrollView.setAdapter(mListAdapter);
-            scrollView.setCallback(this);
-        } else {
-            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
-        }
+        mRecentsContainer.setAdapter(mListAdapter);
+        mRecentsContainer.setCallback(this);
 
         mRecentsScrim = findViewById(R.id.recents_bg_protect);
         mRecentsNoApps = findViewById(R.id.recents_no_apps);
@@ -462,11 +459,7 @@
     }
 
     public void setMinSwipeAlpha(float minAlpha) {
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                = (RecentsScrollView) mRecentsContainer;
-            scrollView.setMinSwipeAlpha(minAlpha);
-        }
+        mRecentsContainer.setMinSwipeAlpha(minAlpha);
     }
 
     private void createCustomAnimations(LayoutTransition transitioner) {
@@ -488,23 +481,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);
@@ -517,14 +510,14 @@
                 }
                 h.thumbnailView.setVisibility(View.VISIBLE);
             }
-            h.thumbnailViewImageBitmap = thumbnail;
+            h.thumbnailViewDrawable = thumbnail;
         }
     }
 
     void onTaskThumbnailLoaded(TaskDescription td) {
         synchronized (td) {
             if (mRecentsContainer != null) {
-                ViewGroup container = mRecentsContainer;
+                ViewGroup container = (ViewGroup) mRecentsContainer;
                 if (container instanceof RecentsScrollView) {
                     container = (ViewGroup) container.findViewById(
                             R.id.recents_linear_layout);
@@ -633,7 +626,7 @@
         final int items = mRecentTaskDescriptions != null
                 ? mRecentTaskDescriptions.size() : 0;
 
-        mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
+        ((View) mRecentsContainer).setVisibility(items > 0 ? View.VISIBLE : View.GONE);
 
         // Set description for accessibility
         int numRecentApps = mRecentTaskDescriptions != null
@@ -650,33 +643,33 @@
     }
 
     public boolean simulateClick(int persistentTaskId) {
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                = (RecentsScrollView) mRecentsContainer;
-            View v = scrollView.findViewForTask(persistentTaskId);
-            if (v != null) {
-                handleOnClick(v);
-                return true;
-            }
+        View v = mRecentsContainer.findViewForTask(persistentTaskId);
+        if (v != null) {
+            handleOnClick(v);
+            return true;
         }
         return false;
     }
 
     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 :
@@ -771,7 +764,7 @@
         popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
             public boolean onMenuItemClick(MenuItem item) {
                 if (item.getItemId() == R.id.recent_remove_item) {
-                    mRecentsContainer.removeViewInLayout(selectedView);
+                    ((ViewGroup) mRecentsContainer).removeViewInLayout(selectedView);
                 } else if (item.getItemId() == R.id.recent_inspect_item) {
                     ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
                     if (viewHolder != null) {
@@ -795,4 +788,26 @@
         });
         popup.show();
     }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+
+        int paddingLeft = mPaddingLeft;
+        final boolean offsetRequired = isPaddingOffsetRequired();
+        if (offsetRequired) {
+            paddingLeft += getLeftPaddingOffset();
+        }
+
+        int left = mScrollX + paddingLeft;
+        int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
+        int top = mScrollY + getFadeTop(offsetRequired);
+        int bottom = top + getFadeHeight(offsetRequired);
+
+        if (offsetRequired) {
+            right += getRightPaddingOffset();
+            bottom += getBottomPaddingOffset();
+        }
+        mRecentsContainer.drawFadedEdges(canvas, left, right, top, bottom);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index ee076d9..6dddc39 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -49,9 +49,10 @@
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
-    private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+    private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
     private HashSet<View> mRecycledViews;
     private int mNumItemsInOneScreenful;
+    private Runnable mOnScrollListener;
 
     public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
@@ -59,7 +60,7 @@
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
 
-        mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
+        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, true);
         mRecycledViews = new HashSet<View>();
     }
 
@@ -112,8 +113,8 @@
             }
             final View view = mAdapter.getView(i, old, mLinearLayout);
 
-            if (mPerformanceHelper != null) {
-                mPerformanceHelper.addViewCallback(view);
+            if (mFadedEdgeDrawHelper != null) {
+                mFadedEdgeDrawHelper.addViewCallback(view);
             }
 
             OnTouchListener noOpListener = new OnTouchListener() {
@@ -243,36 +244,32 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-
-        if (mPerformanceHelper != null) {
-            int paddingLeft = mPaddingLeft;
+    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+        if (mFadedEdgeDrawHelper != null) {
             final boolean offsetRequired = isPaddingOffsetRequired();
-            if (offsetRequired) {
-                paddingLeft += getLeftPaddingOffset();
-            }
-
-            int left = mScrollX + paddingLeft;
-            int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
-            int top = mScrollY + getFadeTop(offsetRequired);
-            int bottom = top + getFadeHeight(offsetRequired);
-
-            if (offsetRequired) {
-                right += getRightPaddingOffset();
-                bottom += getBottomPaddingOffset();
-            }
-            mPerformanceHelper.drawCallback(canvas,
-                    left, right, top, bottom, mScrollX, mScrollY,
+            mFadedEdgeDrawHelper.drawCallback(canvas,
+                    left, right, top + getFadeTop(offsetRequired), bottom, mScrollX, mScrollY,
                     getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
                     0, 0, mPaddingTop);
         }
     }
 
     @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+       super.onScrollChanged(l, t, oldl, oldt);
+       if (mOnScrollListener != null) {
+           mOnScrollListener.run();
+       }
+    }
+
+    public void setOnScrollListener(Runnable listener) {
+        mOnScrollListener = listener;
+    }
+
+    @Override
     public int getVerticalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
         } else {
             return super.getVerticalFadingEdgeLength();
         }
@@ -280,8 +277,8 @@
 
     @Override
     public int getHorizontalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
         } else {
             return super.getHorizontalFadingEdgeLength();
         }
@@ -299,9 +296,8 @@
 
     @Override
     public void onAttachedToWindow() {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.onAttachedToWindowCallback(
-                    mCallback, mLinearLayout, isHardwareAccelerated());
+        if (mFadedEdgeDrawHelper != null) {
+            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
         }
     }
 
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/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 4683030..b56d7be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -424,7 +424,7 @@
                         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",
                         mShowMenu ? "true" : "false"));
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 ceed30e..25ffbd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -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() {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ba8671a..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);
@@ -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/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index c6c4a94..67b2307 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -113,7 +113,7 @@
             uid = _uid;
             packageName = _packageName;
             op = _op;
-            mode = AppOpsManager.MODE_ALLOWED;
+            mode = AppOpsManager.opToDefaultMode(op);
         }
     }
 
@@ -191,7 +191,7 @@
         mHandler = new Handler();
         readState();
     }
-    
+
     public void publish(Context context) {
         mContext = context;
         ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
@@ -379,7 +379,7 @@
                         }
                         repCbs.addAll(cbs);
                     }
-                    if (mode == AppOpsManager.MODE_ALLOWED) {
+                    if (mode == AppOpsManager.opToDefaultMode(op.op)) {
                         // If going into the default mode, prune this op
                         // if there is nothing else interesting in it.
                         pruneOp(op, uid, packageName);
@@ -435,8 +435,8 @@
                     Ops pkgOps = ent.getValue();
                     for (int j=pkgOps.size()-1; j>=0; j--) {
                         Op curOp = pkgOps.valueAt(j);
-                        if (curOp.mode != AppOpsManager.MODE_ALLOWED) {
-                            curOp.mode = AppOpsManager.MODE_ALLOWED;
+                        if (curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
+                            curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
                             changed = true;
                             callbacks = addCallbacks(callbacks, packageName, curOp.op,
                                     mOpModeWatchers.get(curOp.op));
@@ -545,7 +545,7 @@
         synchronized (this) {
             Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
             if (op == null) {
-                return AppOpsManager.MODE_ALLOWED;
+                return AppOpsManager.opToDefaultMode(code);
             }
             return op.mode;
         }
@@ -947,7 +947,7 @@
                             AppOpsManager.OpEntry op = ops.get(j);
                             out.startTag(null, "op");
                             out.attribute(null, "n", Integer.toString(op.getOp()));
-                            if (op.getMode() != AppOpsManager.MODE_ALLOWED) {
+                            if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
                                 out.attribute(null, "m", Integer.toString(op.getMode()));
                             }
                             long time = op.getTime();
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/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 2bca759..8cc80f7 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -105,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;
@@ -141,6 +142,12 @@
 
     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;
@@ -532,8 +539,14 @@
      */
     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);
@@ -760,6 +773,9 @@
     }
 
     public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
         enforceCrossUserPermission(userHandle);
         Intent resolveIntent = new Intent();
         resolveIntent.setComponent(adminName);
@@ -1049,6 +1065,9 @@
     }
 
     public void systemReady() {
+        if (!mHasFeature) {
+            return;
+        }
         synchronized (this) {
             loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
             loadDeviceOwner();
@@ -1137,6 +1156,9 @@
      * @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);
@@ -1180,6 +1202,9 @@
     }
 
     public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
@@ -1187,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);
@@ -1197,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);
@@ -1214,6 +1247,9 @@
     }
 
     public boolean packageHasActiveAdmins(String packageName, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1228,6 +1264,9 @@
     }
 
     public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
@@ -1253,6 +1292,9 @@
     }
 
     public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         validateQualityConstant(quality);
         enforceCrossUserPermission(userHandle);
 
@@ -1270,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;
@@ -1292,6 +1337,9 @@
     }
 
     public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1307,6 +1355,9 @@
     }
 
     public int getPasswordMinimumLength(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1329,6 +1380,9 @@
     }
 
     public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1344,6 +1398,9 @@
     }
 
     public int getPasswordHistoryLength(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1366,6 +1423,9 @@
     }
 
     public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1396,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) {
@@ -1441,6 +1504,9 @@
     }
 
     public long getPasswordExpiration(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0L;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             return getPasswordExpirationLocked(who, userHandle);
@@ -1448,6 +1514,9 @@
     }
 
     public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1463,6 +1532,9 @@
     }
 
     public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1500,6 +1572,9 @@
     }
 
     public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1522,6 +1597,9 @@
     }
 
     public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1537,6 +1615,9 @@
     }
 
     public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1559,6 +1640,9 @@
     }
 
     public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1574,6 +1658,9 @@
     }
 
     public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1596,6 +1683,9 @@
     }
 
     public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1611,6 +1701,9 @@
     }
 
     public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1633,6 +1726,9 @@
     }
 
     public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1648,6 +1744,9 @@
     }
 
     public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int length = 0;
@@ -1670,6 +1769,9 @@
     }
 
     public boolean isActivePasswordSufficient(int userHandle) {
+        if (!mHasFeature) {
+            return true;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1705,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,
@@ -1721,6 +1826,9 @@
     }
 
     public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
@@ -1746,6 +1854,9 @@
     }
 
     public boolean resetPassword(String password, int flags, int userHandle) {
+        if (!mHasFeature) {
+            return false;
+        }
         enforceCrossUserPermission(userHandle);
         int quality;
         synchronized (this) {
@@ -1867,6 +1978,9 @@
     }
 
     public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             if (who == null) {
@@ -1912,6 +2026,9 @@
     }
 
     public long getMaximumTimeToLock(ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return 0;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             long time = 0;
@@ -1937,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.
@@ -2057,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,
@@ -2092,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);
@@ -2122,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);
@@ -2188,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);
             }
@@ -2213,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);
                 }
@@ -2224,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) {
@@ -2274,6 +2410,9 @@
     }
 
     public ComponentName getGlobalProxyAdmin(int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
         enforceCrossUserPermission(userHandle);
         synchronized(this) {
             DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
@@ -2335,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
@@ -2386,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
@@ -2412,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();
     }
@@ -2460,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) {
@@ -2480,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);
@@ -2503,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) {
@@ -2523,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) {
@@ -2544,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
@@ -2564,6 +2727,9 @@
 
     @Override
     public boolean isDeviceOwner(String packageName) {
+        if (!mHasFeature) {
+            return false;
+        }
         synchronized (this) {
             return mDeviceOwner != null
                     && mDeviceOwner.getPackageName().equals(packageName);
@@ -2572,6 +2738,9 @@
 
     @Override
     public String getDeviceOwner() {
+        if (!mHasFeature) {
+            return null;
+        }
         synchronized (this) {
             if (mDeviceOwner != null) {
                 return mDeviceOwner.getPackageName();
@@ -2582,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/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 064b3a8..1f64101 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1843,16 +1843,17 @@
                 // bottom of the activity stack.  This also keeps it
                 // correctly ordered with any activities we previously
                 // moved.
-                TaskRecord bottomTask = mTaskHistory.get(0);
-                ActivityRecord p = bottomTask.mActivities.get(0);
-                if (target.taskAffinity != null
-                        && target.taskAffinity.equals(p.task.affinity)) {
+                final ActivityRecord bottom =
+                        !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
+                        mTaskHistory.get(0).mActivities.get(0) : null;
+                if (bottom != null && target.taskAffinity != null
+                        && target.taskAffinity.equals(bottom.task.affinity)) {
                     // If the activity currently at the bottom has the
                     // same task affinity as the one we are moving,
                     // then merge it into the same task.
-                    target.setTask(p.task, p.thumbHolder, false);
+                    target.setTask(bottom.task, bottom.thumbHolder, false);
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
-                            + " out to bottom task " + p.task);
+                            + " out to bottom task " + bottom.task);
                 } else {
                     target.setTask(createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
                             null, false), null, false);
@@ -1868,7 +1869,7 @@
                 boolean noOptions = canMoveOptions;
                 final int start = replyChainEnd < 0 ? i : replyChainEnd;
                 for (int srcPos = start; srcPos >= i; --srcPos) {
-                    p = activities.get(srcPos);
+                    final ActivityRecord p = activities.get(srcPos);
                     if (p.finishing) {
                         continue;
                     }
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..7a456f7 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
@@ -399,9 +407,9 @@
     }
 
     public void makeInactive(ProcessStatsService tracker) {
-        if (thread != null) {
-            thread = null;
-            final ProcessStats.ProcessState origBase = baseProcessTracker;
+        thread = null;
+        final ProcessStats.ProcessState origBase = baseProcessTracker;
+        if (origBase != null) {
             if (origBase != null) {
                 origBase.setState(ProcessStats.STATE_NOTHING,
                         tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
@@ -559,7 +567,16 @@
      */
     public boolean addPackage(String pkg, ProcessStatsService tracker) {
         if (!pkgList.containsKey(pkg)) {
-            pkgList.put(pkg, tracker.getProcessStateLocked(pkg, info.uid, processName));
+            if (baseProcessTracker != null) {
+                ProcessStats.ProcessState state = tracker.getProcessStateLocked(
+                        pkg, info.uid, processName);
+                pkgList.put(pkg, state);
+                if (state != baseProcessTracker) {
+                    state.makeActive();
+                }
+            } else {
+                pkgList.put(pkg, null);
+            }
             return true;
         }
         return false;
@@ -584,25 +601,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 (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..0a1685c 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -30,6 +30,7 @@
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TimeUtils;
 import com.android.internal.app.IProcessStats;
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BackgroundThread;
@@ -39,6 +40,7 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -313,7 +315,8 @@
         return true;
     }
 
-    private ArrayList<String> getCommittedFiles(int minNum, boolean inclAll) {
+    private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
+            boolean inclCheckedIn) {
         File[] files = mBaseDir.listFiles();
         if (files == null || files.length <= minNum) {
             return null;
@@ -325,11 +328,11 @@
             File file = files[i];
             String fileStr = file.getPath();
             if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
-            if (!inclAll && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
+            if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
                 if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
                 continue;
             }
-            if (fileStr.equals(currentFile)) {
+            if (!inclCurrent && fileStr.equals(currentFile)) {
                 if (DEBUG) Slog.d(TAG, "Skipping: current stats");
                 continue;
             }
@@ -340,7 +343,7 @@
     }
 
     public void trimHistoricStatesWriteLocked() {
-        ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, true);
+        ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true);
         if (filesArray == null) {
             return;
         }
@@ -409,6 +412,8 @@
     }
 
     public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
+        mAm.mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
         Parcel current = Parcel.obtain();
         mWriteLock.lock();
         try {
@@ -417,7 +422,7 @@
                 mProcessStats.writeToParcel(current, 0);
             }
             if (historic != null) {
-                ArrayList<String> files = getCommittedFiles(0, true);
+                ArrayList<String> files = getCommittedFiles(0, false, true);
                 if (files != null) {
                     for (int i=files.size()-1; i>=0; i--) {
                         try {
@@ -436,6 +441,76 @@
         return current.marshall();
     }
 
+    public ParcelFileDescriptor getStatsOverTime(long minTime) {
+        mAm.mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+        mWriteLock.lock();
+        try {
+            Parcel current = Parcel.obtain();
+            long curTime;
+            synchronized (mAm) {
+                mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+                mProcessStats.writeToParcel(current, 0);
+                curTime = mProcessStats.mTimePeriodEndRealtime
+                        - mProcessStats.mTimePeriodStartRealtime;
+            }
+            if (curTime < minTime) {
+                // Need to add in older stats to reach desired time.
+                ArrayList<String> files = getCommittedFiles(0, false, true);
+                if (files.size() > 0) {
+                    current.setDataPosition(0);
+                    ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
+                    current.recycle();
+                    int i = 0;
+                    while (i < files.size() && (stats.mTimePeriodEndRealtime
+                            - stats.mTimePeriodStartRealtime) < minTime) {
+                        AtomicFile file = new AtomicFile(new File(files.get(i)));
+                        i++;
+                        ProcessStats moreStats = new ProcessStats(false);
+                        readLocked(moreStats, file);
+                        if (moreStats.mReadError == null) {
+                            stats.add(moreStats);
+                            StringBuilder sb = new StringBuilder();
+                            sb.append("Added stats: ");
+                            sb.append(moreStats.mTimePeriodStartClockStr);
+                            sb.append(", over ");
+                            TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime
+                                    - moreStats.mTimePeriodStartRealtime, sb);
+                            Slog.i(TAG, sb.toString());
+                        } else {
+                            Slog.w(TAG, "Failure reading " + files.get(i) + "; "
+                                    + moreStats.mReadError);
+                            continue;
+                        }
+                    }
+                    current = Parcel.obtain();
+                    stats.writeToParcel(current, 0);
+                }
+            }
+            final byte[] outData = current.marshall();
+            current.recycle();
+            final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+            Thread thr = new Thread("ProcessStats pipe output") {
+                public void run() {
+                    FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
+                    try {
+                        fout.write(outData);
+                        fout.close();
+                    } catch (IOException e) {
+                        Slog.w(TAG, "Failure writing pipe", e);
+                    }
+                }
+            };
+            thr.start();
+            return fds[0];
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed building output pipe", e);
+        } finally {
+            mWriteLock.unlock();
+        }
+        return null;
+    }
+
     public int getCurrentMemoryState() {
         synchronized (mAm) {
             return mLastMemOnlyState;
@@ -445,7 +520,8 @@
     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] [--full-details] [--current] [--one-day]");
+        pw.println("    [--commit] [--reset] [--clear] [--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.");
@@ -454,8 +530,12 @@
         pw.println("  --csv-proc: pers, top, fore, vis, precept, backup,");
         pw.println("    service, home, prev, cached");
         pw.println("  --details: dump all execution details, not just summary.");
+        pw.println("  --full-details: dump only detail information, for all saved state.");
         pw.println("  --current: only dump current state.");
+        pw.println("  --one-day: dump stats aggregated across about one day.");
         pw.println("  --commit: commit current stats to disk and reset to start new stats.");
+        pw.println("  --reset: reset current stats, without committing.");
+        pw.println("  --clear: clear all stats; does both --reset and deletes old stats.");
         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.");
@@ -480,7 +560,9 @@
         boolean isCsv = false;
         boolean currentOnly = false;
         boolean dumpDetails = false;
+        boolean dumpFullDetails = false;
         boolean dumpAll = false;
+        boolean oneDay = false;
         String reqPackage = null;
         boolean csvSepScreenStats = false;
         int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON};
@@ -548,20 +630,48 @@
                     csvSepProcStats = sep[0];
                 } else if ("--details".equals(arg)) {
                     dumpDetails = true;
+                } else if ("--full-details".equals(arg)) {
+                    dumpFullDetails = true;
+                } else if ("--one-day".equals(arg)) {
+                    oneDay = true;
                 } 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 ("--clear".equals(arg)) {
+                    synchronized (mAm) {
+                        mProcessStats.resetSafely();
+                        ArrayList<String> files = getCommittedFiles(0, true, true);
+                        if (files != null) {
+                            for (int fi=0; fi<files.size(); fi++) {
+                                (new File(files.get(fi))).delete();
+                            }
+                        }
+                        pw.println("All process stats cleared.");
+                    }
                     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);
@@ -640,13 +750,36 @@
                 */
             }
             return;
+        } else if (oneDay) {
+            ParcelFileDescriptor pfd = getStatsOverTime(24*60*60*1000);
+            if (pfd == null) {
+                pw.println("Unable to build stats!");
+                return;
+            }
+            ProcessStats stats = new ProcessStats(false);
+            InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+            stats.read(stream);
+            if (stats.mReadError != null) {
+                pw.print("Failure reading: "); pw.println(stats.mReadError);
+                return;
+            }
+            if (isCompact) {
+                stats.dumpCheckinLocked(pw, reqPackage);
+            } else {
+                if (dumpDetails || dumpFullDetails) {
+                    stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll);
+                } else {
+                    stats.dumpSummaryLocked(pw, reqPackage, now);
+                }
+            }
+            return;
         }
 
         boolean sepNeeded = false;
         if (!currentOnly || isCheckin) {
             mWriteLock.lock();
             try {
-                ArrayList<String> files = getCommittedFiles(0, !isCheckin);
+                ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
                 if (files != null) {
                     for (int i=0; i<files.size(); i++) {
                         if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
@@ -680,7 +813,11 @@
                                 // Don't really need to lock because we uniquely own this object.
                                 // Always dump summary here, dumping all details is just too
                                 // much crud.
-                                processStats.dumpSummaryLocked(pw, reqPackage, now);
+                                if (dumpFullDetails) {
+                                    mProcessStats.dumpLocked(pw, reqPackage, now, false, false);
+                                } else {
+                                    processStats.dumpSummaryLocked(pw, reqPackage, now);
+                                }
                             }
                             if (isCheckin) {
                                 // Rename file suffix to mark that it has checked in.
@@ -706,8 +843,8 @@
                         pw.println();
                         pw.println("CURRENT STATS:");
                     }
-                    if (dumpDetails) {
-                        mProcessStats.dumpLocked(pw, reqPackage, now, dumpAll);
+                    if (dumpDetails || dumpFullDetails) {
+                        mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll);
                         if (dumpAll) {
                             pw.print("  mFile="); pw.println(mFile.getBaseFile());
                         }
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
index c33bfb7..ddc5046 100644
--- a/services/java/com/android/server/print/PrintManagerService.java
+++ b/services/java/com/android/server/print/PrintManagerService.java
@@ -33,6 +33,7 @@
 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;
@@ -70,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);
@@ -105,95 +108,65 @@
         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);
@@ -443,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
@@ -471,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 8869cbe..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;
@@ -690,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();
@@ -705,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();
@@ -719,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();
@@ -733,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();
@@ -746,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);
                 }
@@ -760,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 7a56e6b..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,79 @@
         }
     }
 
+    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;
@@ -328,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();
@@ -593,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);
         }
@@ -1088,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);
             }
@@ -1109,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);
             }
         }
 
@@ -1255,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/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index dbd42af..69ff449 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -923,7 +923,8 @@
                     //that was created later or a window at the top of the list of
                     //windows associated with this token.
                     if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
-                            "Adding window " + win + " at " + (newIdx + 1) + " of " + N);
+                            "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.
@@ -1044,7 +1045,7 @@
             }
         }
         if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
-                "Adding window " + win + " at " + i + " of " + N);
+                "Based on layer: Adding window " + win + " at " + i + " of " + N);
         windows.add(i, win);
         mWindowsChanged = true;
         return tokenWindowsPos;
@@ -1063,7 +1064,7 @@
         }
         i++;
         if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
-                "Adding window " + win + " at " + i + " of " + windows.size());
+                "Free window: Adding window " + win + " at " + i + " of " + windows.size());
         windows.add(i, win);
         mWindowsChanged = true;
     }
@@ -1130,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;
@@ -1185,16 +1188,15 @@
         // same display. Or even when the current IME/target are not on the same screen as the next
         // IME/target. For now only look for input windows on the main screen.
         WindowList windows = getDefaultWindowListLocked();
-        final int N = windows.size();
         WindowState w = null;
-        int i = N;
-        while (i > 0) {
-            i--;
-            w = windows.get(i);
+        int i;
+        for (i = windows.size() - 1; i >= 0; --i) {
+            WindowState win = windows.get(i);
 
             if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG, "Checking window @" + i
-                    + " " + w + " fl=0x" + Integer.toHexString(w.mAttrs.flags));
-            if (canBeImeTarget(w)) {
+                    + " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags));
+            if (canBeImeTarget(win)) {
+                w = win;
                 //Slog.i(TAG, "Putting input method here!");
 
                 // Yet more tricksyness!  If this window is a "starting"
@@ -7081,19 +7083,17 @@
                         }
                     }
 
-                    if (lastFocus != newFocus) {
-                        //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();
-                        }
+                    //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) {
-                            if (DEBUG_FOCUS_LIGHT) 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;
 
@@ -10277,14 +10277,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/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