Merge "Add WorkSource capability to LocationManager"
diff --git a/api/current.txt b/api/current.txt
index e7a518f..9b5c376 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -72,6 +72,7 @@
     field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
     field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
     field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
+    field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
     field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
     field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
     field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
@@ -793,6 +794,7 @@
     field public static final int path = 16842794; // 0x101002a
     field public static final int pathPattern = 16842796; // 0x101002c
     field public static final int pathPrefix = 16842795; // 0x101002b
+    field public static final int paymentService = 16843749; // 0x10103e5
     field public static final int permission = 16842758; // 0x1010006
     field public static final int permissionFlags = 16843719; // 0x10103c7
     field public static final int permissionGroup = 16842762; // 0x101000a
@@ -3057,6 +3059,7 @@
     method public void setRepeating(int, long, long, android.app.PendingIntent);
     method public void setTime(long);
     method public void setTimeZone(java.lang.String);
+    method public void setWindow(int, long, long, android.app.PendingIntent);
     field public static final int ELAPSED_REALTIME = 3; // 0x3
     field public static final int ELAPSED_REALTIME_WAKEUP = 2; // 0x2
     field public static final deprecated long INTERVAL_DAY = 86400000L; // 0x5265c00L
@@ -6296,6 +6299,7 @@
     field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
     field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
+    field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
     field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
@@ -7115,6 +7119,7 @@
     field public static final java.lang.String FEATURE_LOCATION_NETWORK = "android.hardware.location.network";
     field public static final java.lang.String FEATURE_MICROPHONE = "android.hardware.microphone";
     field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
+    field public static final java.lang.String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
     field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
     field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
     field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
@@ -14741,6 +14746,31 @@
 
 }
 
+package android.nfc.cardemulation {
+
+  public abstract class HostApduService extends android.app.Service {
+    ctor public HostApduService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onDeactivated(int);
+    method public abstract byte[] processCommandApdu(byte[], int);
+    method public final void sendResponseApdu(byte[]);
+    field public static final int DEACTIVATION_DESELECTED = 1; // 0x1
+    field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
+    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.HostApduService";
+    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.HostApduService";
+  }
+
+  public abstract class SeApduService extends android.app.Service {
+    ctor public SeApduService();
+    method public abstract void onAidSelected(byte[]);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onHciTransactionEvent(byte[], byte[]);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.SeApduService";
+    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.SeApduService";
+  }
+
+}
+
 package android.nfc.tech {
 
    abstract class BasicTagTechnology implements android.nfc.tech.TagTechnology {
@@ -18026,6 +18056,7 @@
     method public void setUserRestriction(java.lang.String, boolean);
     method public void setUserRestrictions(android.os.Bundle);
     method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
+    field public static final java.lang.String DISALLOW_APP_RESTRICTIONS = "no_app_restrictions";
     field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
     field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
     field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
@@ -18559,14 +18590,14 @@
     ctor public PrintAttributes.Resolution(java.lang.String, java.lang.CharSequence, int, int);
     method public int getHorizontalDpi();
     method public java.lang.String getId();
-    method public java.lang.CharSequence getLabel(android.content.pm.PackageManager);
+    method public java.lang.CharSequence getLabel();
     method public int getVerticalDpi();
   }
 
   public static final class PrintAttributes.Tray {
     ctor public PrintAttributes.Tray(java.lang.String, java.lang.CharSequence);
     method public java.lang.String getId();
-    method public java.lang.CharSequence getLabel(android.content.pm.PackageManager);
+    method public java.lang.CharSequence getLabel();
   }
 
   public abstract class PrintDocumentAdapter {
@@ -18627,7 +18658,6 @@
     field public static final int PRINT_JOB_ID_UNDEFINED = -1; // 0xffffffff
     field public static final int STATE_CANCELED = 6; // 0x6
     field public static final int STATE_COMPLETED = 4; // 0x4
-    field public static final int STATE_CREATED = 1; // 0x1
     field public static final int STATE_FAILED = 5; // 0x5
     field public static final int STATE_QUEUED = 2; // 0x2
     field public static final int STATE_STARTED = 3; // 0x3
@@ -25597,6 +25627,7 @@
 
   public final class InputDevice implements android.os.Parcelable {
     method public int describeContents();
+    method public int getControllerNumber();
     method public java.lang.String getDescriptor();
     method public static android.view.InputDevice getDevice(int);
     method public static int[] getDeviceIds();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index d945216..d78572b 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -99,6 +99,7 @@
                 "       am clear-debug-app\n" +
                 "       am monitor [--gdb <port>]\n" +
                 "       am hang [--allow-restart]\n" +
+                "       am restart\n" +
                 "       am screen-compat [on|off] <PACKAGE>\n" +
                 "       am to-uri [INTENT]\n" +
                 "       am to-intent-uri [INTENT]\n" +
@@ -186,6 +187,8 @@
                 "am hang: hang the system.\n" +
                 "    --allow-restart: allow watchdog to perform normal system restart\n" +
                 "\n" +
+                "am restart: restart the user-space system.\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" +
@@ -290,6 +293,8 @@
             runMonitor();
         } else if (op.equals("hang")) {
             runHang();
+        } else if (op.equals("restart")) {
+            runRestart();
         } else if (op.equals("screen-compat")) {
             runScreenCompat();
         } else if (op.equals("to-uri")) {
@@ -1377,6 +1382,17 @@
         mAm.hang(new Binder(), allowRestart);
     }
 
+    private void runRestart() throws Exception {
+        String opt;
+        while ((opt=nextOption()) != null) {
+            System.err.println("Error: Unknown option: " + opt);
+            return;
+        }
+
+        System.out.println("Restart the system...");
+        mAm.restart();
+    }
+
     private void runScreenCompat() throws Exception {
         String mode = nextArgRequired();
         boolean enabled;
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index bb26443..473b60c 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -24,6 +24,9 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Command that sends key events to the device, either by their keycode, or by
  * desired character output.
@@ -31,6 +34,21 @@
 
 public class Input {
     private static final String TAG = "Input";
+    private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: ";
+
+    private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{
+        put("keyboard", InputDevice.SOURCE_KEYBOARD);
+        put("dpad", InputDevice.SOURCE_DPAD);
+        put("gamepad", InputDevice.SOURCE_GAMEPAD);
+        put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN);
+        put("mouse", InputDevice.SOURCE_MOUSE);
+        put("stylus", InputDevice.SOURCE_STYLUS);
+        put("trackball", InputDevice.SOURCE_TRACKBALL);
+        put("touchpad", InputDevice.SOURCE_TOUCHPAD);
+        put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION);
+        put("joystick", InputDevice.SOURCE_JOYSTICK);
+    }};
+
 
     /**
      * Command-line entry point.
@@ -47,86 +65,71 @@
             return;
         }
 
-        String command = args[0];
+        int index = 0;
+        String command = args[index];
+        int inputSource = InputDevice.SOURCE_UNKNOWN;
+        if (SOURCES.containsKey(command)) {
+            inputSource = SOURCES.get(command);
+            index++;
+            command = args[index];
+        }
+        final int length = args.length - index;
 
         try {
             if (command.equals("text")) {
-                if (args.length == 2) {
-                    sendText(args[1]);
+                if (length == 2) {
+                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
+                    sendText(inputSource, args[index+1]);
                     return;
                 }
             } else if (command.equals("keyevent")) {
-                if (args.length >= 2) {
-                    final boolean longpress = "--longpress".equals(args[1]);
-                    final int start = longpress ? 2 : 1;
-                    if (args.length > start) {
-                        for (int i = start; i < args.length; i++) {
+                if (length >= 2) {
+                    final boolean longpress = "--longpress".equals(args[index + 1]);
+                    final int start = longpress ? index + 2 : index + 1;
+                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
+                    if (length > start) {
+                        for (int i = start; i < length; i++) {
                             int keyCode = KeyEvent.keyCodeFromString(args[i]);
                             if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
                                 keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
                             }
-                            sendKeyEvent(keyCode, longpress);
+                            sendKeyEvent(inputSource, keyCode, longpress);
                         }
                         return;
                     }
                 }
             } else if (command.equals("tap")) {
-                if (args.length == 3) {
-                    sendTap(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]));
+                if (length == 3) {
+                    inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+                    sendTap(inputSource, Float.parseFloat(args[index+1]),
+                            Float.parseFloat(args[index+2]));
                     return;
                 }
             } else if (command.equals("swipe")) {
-                if (args.length == 5) {
-                    sendSwipe(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]),
-                            Float.parseFloat(args[3]), Float.parseFloat(args[4]), -1);
+                int duration = -1;
+                inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+                switch (length) {
+                    case 6:
+                        duration = Integer.parseInt(args[index+5]);
+                    case 5:
+                        sendSwipe(inputSource,
+                                Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
+                                Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
+                                duration);
+                        return;
+                }
+            } else if (command.equals("press")) {
+                inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
+                if (length == 1) {
+                    sendTap(inputSource, 0.0f, 0.0f);
                     return;
                 }
-            } else if (command.equals("touchscreen") || command.equals("touchpad")
-                    || command.equals("touchnavigation")) {
-                // determine input source
-                int inputSource = InputDevice.SOURCE_TOUCHSCREEN;
-                if (command.equals("touchpad")) {
-                    inputSource = InputDevice.SOURCE_TOUCHPAD;
-                } else if (command.equals("touchnavigation")) {
-                    inputSource = InputDevice.SOURCE_TOUCH_NAVIGATION;
-                }
-                // determine subcommand
-                if (args.length > 1) {
-                    String subcommand = args[1];
-                    if (subcommand.equals("tap")) {
-                        if (args.length == 4) {
-                            sendTap(inputSource, Float.parseFloat(args[2]),
-                                    Float.parseFloat(args[3]));
-                            return;
-                        }
-                    } else if (subcommand.equals("swipe")) {
-                        if (args.length == 6) {
-                            sendSwipe(inputSource, Float.parseFloat(args[2]),
-                                    Float.parseFloat(args[3]), Float.parseFloat(args[4]),
-                                    Float.parseFloat(args[5]), -1);
-                            return;
-                        } else if (args.length == 7) {
-                            sendSwipe(inputSource, Float.parseFloat(args[2]),
-                                    Float.parseFloat(args[3]), Float.parseFloat(args[4]),
-                                    Float.parseFloat(args[5]), Integer.parseInt(args[6]));
-                            return;
-                        }
-                    }
-                }
-            } else if (command.equals("trackball")) {
-                // determine subcommand
-                if (args.length > 1) {
-                    String subcommand = args[1];
-                    if (subcommand.equals("press")) {
-                        sendTap(InputDevice.SOURCE_TRACKBALL, 0.0f, 0.0f);
-                        return;
-                    } else if (subcommand.equals("roll")) {
-                        if (args.length == 4) {
-                            sendMove(InputDevice.SOURCE_TRACKBALL, Float.parseFloat(args[2]),
-                                    Float.parseFloat(args[3]));
-                            return;
-                        }
-                    }
+            } else if (command.equals("roll")) {
+                inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
+                if (length == 3) {
+                    sendMove(inputSource, Float.parseFloat(args[index+1]),
+                            Float.parseFloat(args[index+2]));
+                    return;
                 }
             } else {
                 System.err.println("Error: Unknown command: " + command);
@@ -135,7 +138,7 @@
             }
         } catch (NumberFormatException ex) {
         }
-        System.err.println("Error: Invalid arguments for command: " + command);
+        System.err.println(INVALID_ARGUMENTS + command);
         showUsage();
     }
 
@@ -145,7 +148,7 @@
      *
      * @param text is a string of characters you want to input to the device.
      */
-    private void sendText(String text) {
+    private void sendText(int source, String text) {
 
         StringBuffer buff = new StringBuffer(text);
 
@@ -157,7 +160,7 @@
                     buff.setCharAt(i, ' ');
                     buff.deleteCharAt(--i);
                 }
-            } 
+            }
             if (buff.charAt(i) == '%') {
                 escapeFlag = true;
             }
@@ -168,21 +171,25 @@
         KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
         KeyEvent[] events = kcm.getEvents(chars);
         for(int i = 0; i < events.length; i++) {
-            injectKeyEvent(events[i]);
+            KeyEvent e = events[i];
+            if (source != e.getSource()) {
+                e.setSource(source);
+            }
+            injectKeyEvent(e);
         }
     }
 
-    private void sendKeyEvent(int keyCode, boolean longpress) {
+    private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) {
         long now = SystemClock.uptimeMillis();
         injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
-                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
+                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
         if (longpress) {
             injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0,
                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,
-                    InputDevice.SOURCE_KEYBOARD));
+                    inputSource));
         }
         injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
-                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
+                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
     }
 
     private void sendTap(int inputSource, float x, float y) {
@@ -206,7 +213,7 @@
                     lerp(y1, y2, alpha), 1.0f);
             now = SystemClock.uptimeMillis();
         }
-        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x1, y1, 0.0f);
+        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
     }
 
     /**
@@ -257,14 +264,26 @@
         return (b - a) * alpha + a;
     }
 
+    private static final int getSource(int inputSource, int defaultSource) {
+        return inputSource == -1 ? defaultSource : inputSource;
+    }
+
     private void showUsage() {
-        System.err.println("usage: input ...");
-        System.err.println("       input text <string>");
-        System.err.println("       input keyevent [--longpress] <key code number or name> ...");
-        System.err.println("       input [touchscreen|touchpad|touchnavigation] tap <x> <y>");
-        System.err.println("       input [touchscreen|touchpad|touchnavigation] swipe "
-                + "<x1> <y1> <x2> <y2> [duration(ms)]");
-        System.err.println("       input trackball press");
-        System.err.println("       input trackball roll <dx> <dy>");
+        System.err.println("Usage: input [<source>] <command> [<arg>...]");
+        System.err.println();
+        System.err.println("The sources are: ");
+        for (String src : SOURCES.keySet()) {
+            System.err.println("      " + src);
+        }
+        System.err.println();
+        System.err.println("The commands and default sources are:");
+        System.err.println("      text <string> (Default: touchscreen)");
+        System.err.println("      keyevent [--longpress] <key code number or name> ..."
+                + " (Default: keyboard)");
+        System.err.println("      tap <x> <y> (Default: touchscreen)");
+        System.err.println("      swipe <x1> <y1> <x2> <y2> [duration(ms)]"
+                + " (Default: touchscreen)");
+        System.err.println("      press (Default: trackball)");
+        System.err.println("      roll <dx> <dy> (Default: trackball)");
     }
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index acfcb40..404f6aa 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1972,6 +1972,13 @@
             reply.writeNoException();
             return true;
         }
+
+        case RESTART_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            restart();
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -4520,5 +4527,15 @@
         reply.recycle();
     }
 
+    public void restart() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(RESTART_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index dbccbeb..d9c3775 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -84,9 +84,15 @@
      */
     public static final int ELAPSED_REALTIME = 3;
 
+    /** @hide */
+    public static final long WINDOW_EXACT = 0;
+    /** @hide */
+    public static final long WINDOW_HEURISTIC = -1;
+
     private final IAlarmManager mService;
     private final boolean mAlwaysExact;
 
+
     /**
      * package private on purpose
      */
@@ -96,9 +102,15 @@
         final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
         mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KEY_LIME_PIE);
     }
-    
+
+    private long legacyExactLength() {
+        return (mAlwaysExact ? WINDOW_EXACT : WINDOW_HEURISTIC);
+    }
+
     /**
-     * Schedule an alarm.  <b>Note: for timing operations (ticks, timeouts,
+     * TBW: discussion of fuzzy nature of alarms in KLP+.
+     *
+     * <p>Schedule an alarm.  <b>Note: for timing operations (ticks, timeouts,
      * etc) it is easier and much more efficient to use
      * {@link android.os.Handler}.</b>  If there is already an alarm scheduled
      * for the same IntentSender, it will first be canceled.
@@ -130,7 +142,9 @@
      * IntentSender.getBroadcast()}.
      *
      * @see android.os.Handler
+     * @see #setExact
      * @see #setRepeating
+     * @see #setWindow
      * @see #cancel
      * @see android.content.Context#sendBroadcast
      * @see android.content.Context#registerReceiver
@@ -141,7 +155,7 @@
      * @see #RTC_WAKEUP
      */
     public void set(int type, long triggerAtMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, 0, operation, mAlwaysExact);
+        setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation);
     }
 
     /**
@@ -182,6 +196,8 @@
      *
      * @see android.os.Handler
      * @see #set
+     * @see #setExact
+     * @see #setWindow
      * @see #cancel
      * @see android.content.Context#sendBroadcast
      * @see android.content.Context#registerReceiver
@@ -193,7 +209,42 @@
      */
     public void setRepeating(int type, long triggerAtMillis,
             long intervalMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, intervalMillis, operation, mAlwaysExact);
+        setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, operation);
+    }
+
+    /**
+     * Schedule an alarm to be delivered within a given window of time.
+     *
+     * TBW: clean up these docs
+     *
+     * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or
+     *        RTC_WAKEUP.
+     * @param windowStartMillis The earliest time, in milliseconds, that the alarm should
+     *        be delivered, expressed in the appropriate clock's units (depending on the alarm
+     *        type).
+     * @param windowLengthMillis The length of the requested delivery window,
+     *        in milliseconds.  The alarm will be delivered no later than this many
+     *        milliseconds after the windowStartMillis time.  Note that this parameter
+     *        is a <i>duration,</i> not the timestamp of the end of the window.
+     * @param operation Action to perform when the alarm goes off;
+     *        typically comes from {@link PendingIntent#getBroadcast
+     *        IntentSender.getBroadcast()}.
+     *
+     * @see #set
+     * @see #setExact
+     * @see #setRepeating
+     * @see #cancel
+     * @see android.content.Context#sendBroadcast
+     * @see android.content.Context#registerReceiver
+     * @see android.content.Intent#filterEquals
+     * @see #ELAPSED_REALTIME
+     * @see #ELAPSED_REALTIME_WAKEUP
+     * @see #RTC
+     * @see #RTC_WAKEUP
+     */
+    public void setWindow(int type, long windowStartMillis, long windowLengthMillis,
+            PendingIntent operation) {
+        setImpl(type, windowStartMillis, windowLengthMillis, 0, operation);
     }
 
     /**
@@ -201,13 +252,13 @@
      * to the precise time specified.
      */
     public void setExact(int type, long triggerAtMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, 0, operation, true);
+        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, operation);
     }
 
-    private void setImpl(int type, long triggerAtMillis, long intervalMillis,
-            PendingIntent operation, boolean isExact) {
+    private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
+            PendingIntent operation) {
         try {
-            mService.set(type, triggerAtMillis, intervalMillis, operation, isExact);
+            mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation);
         } catch (RemoteException ex) {
         }
     }
@@ -300,7 +351,7 @@
     @Deprecated
     public void setInexactRepeating(int type, long triggerAtMillis,
             long intervalMillis, PendingIntent operation) {
-        setRepeating(type, triggerAtMillis, intervalMillis, operation);
+        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, operation);
     }
     
     /**
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 19858dc..3eda58c 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -396,6 +396,8 @@
 
     public void reportActivityFullyDrawn(IBinder token) throws RemoteException;
 
+    public void restart() throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -676,4 +678,5 @@
     int CONVERT_TO_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+174;
     int NOTIFY_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+175;
     int REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+176;
+    int RESTART_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+177;
 }
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index 3a2b215..0a49ddf 100644
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -24,7 +24,9 @@
  * {@hide}
  */
 interface IAlarmManager {
-    void set(int type, long triggerAtTime, long interval, in PendingIntent operation, boolean isExact);
+	/** windowLength == 0 means exact; windowLength < 0 means the let the OS decide */
+    void set(int type, long triggerAtTime, long windowLength,
+            long interval, in PendingIntent operation);
     void setTime(long millis);
     void setTimeZone(String zone);
     void remove(in PendingIntent operation);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index bffbb51..e70ad1c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -457,6 +457,37 @@
     public static final String EXTRA_PEOPLE = "android.people";
 
     /**
+     * @hide
+     * Extra added by NotificationManagerService to indicate whether a NotificationScorer
+     * modified the Notifications's score.
+     */
+    public static final String EXTRA_SCORE_MODIFIED = "android.scoreModified";
+
+    /**
+     * Notification extra to specify heads up display preference.
+     * @hide
+     */
+    public static final String EXTRA_AS_HEADS_UP = "headsup";
+
+    /**
+     * Value for {@link #EXTRA_AS_HEADS_UP} indicating that heads up display is not appropriate.
+     * @hide
+     */
+    public static final int HEADS_UP_NEVER = 0;
+
+    /**
+     * Default value for {@link #EXTRA_AS_HEADS_UP} indicating that heads up display is appropriate.
+     * @hide
+     */
+    public static final int HEADS_UP_ALLOWED = 1;
+
+    /**
+     * Value for {@link #EXTRA_AS_HEADS_UP} that advocates for heads up display.
+     * @hide
+     */
+    public static final int HEADS_UP_REQUESTED = 2;
+
+    /**
      * Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
      */
     public static class Action implements Parcelable {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a954f59..324e351 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1896,6 +1896,11 @@
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
+     * <p>May include the following extras:
+     * <ul>
+     * <li> {@link #EXTRA_SHUTDOWN_USERSPACE_ONLY} a boolean that is set to true if this
+     * shutdown is only for userspace processes.  If not set, assumed to be false.
+     * </ul>
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
@@ -3260,6 +3265,15 @@
      */
     public static final String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
 
+    /**
+     * Optional extra for {@link #ACTION_SHUTDOWN} that allows the sender to qualify that
+     * this shutdown is only for the user space of the system, not a complete shutdown.
+     * Hardware should not be shut down when this is true.  The default if not supplied
+     * is false.
+     */
+    public static final String EXTRA_SHUTDOWN_USERSPACE_ONLY
+            = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 36b1abc..5760a5d 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -733,10 +733,15 @@
      * @see #addDataScheme
      */
     public final void addDataSchemeSpecificPart(String ssp, int type) {
+        addDataSchemeSpecificPart(new PatternMatcher(ssp, type));
+    }
+
+    /** @hide */
+    public final void addDataSchemeSpecificPart(PatternMatcher ssp) {
         if (mDataSchemeSpecificParts == null) {
             mDataSchemeSpecificParts = new ArrayList<PatternMatcher>();
         }
-        mDataSchemeSpecificParts.add(new PatternMatcher(ssp, type));
+        mDataSchemeSpecificParts.add(ssp);
     }
 
     /**
@@ -806,10 +811,15 @@
      * @see #addDataScheme
      */
     public final void addDataAuthority(String host, String port) {
+        if (port != null) port = port.intern();
+        addDataAuthority(new AuthorityEntry(host.intern(), port));
+    }
+
+    /** @hide */
+    public final void addDataAuthority(AuthorityEntry ent) {
         if (mDataAuthorities == null) mDataAuthorities =
                 new ArrayList<AuthorityEntry>();
-        if (port != null) port = port.intern();
-        mDataAuthorities.add(new AuthorityEntry(host.intern(), port));
+        mDataAuthorities.add(ent);
     }
 
     /**
@@ -874,8 +884,13 @@
      * @see #addDataAuthority
      */
     public final void addDataPath(String path, int type) {
+        addDataPath(new PatternMatcher(path.intern(), type));
+    }
+
+    /** @hide */
+    public final void addDataPath(PatternMatcher path) {
         if (mDataPaths == null) mDataPaths = new ArrayList<PatternMatcher>();
-        mDataPaths.add(new PatternMatcher(path.intern(), type));
+        mDataPaths.add(path);
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8a8751e..81f860e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -955,6 +955,14 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports host-
+     * based NFC card emulation.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device includes an accelerometer.
      */
     @SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ce7addc..aaa2640 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -45,9 +45,6 @@
 import java.security.PublicKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.CertPath;
-import java.security.cert.X509Certificate;
 import java.security.spec.EncodedKeySpec;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
@@ -2440,7 +2437,7 @@
 
             if (parser.getName().equals("intent-filter")) {
                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
-                if (!parseIntent(res, parser, attrs, flags, intent, outError, !receiver)) {
+                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
                     return null;
                 }
                 if (intent.countActions() == 0) {
@@ -2450,6 +2447,21 @@
                 } else {
                     a.intents.add(intent);
                 }
+            } else if (!receiver && parser.getName().equals("preferred")) {
+                ActivityIntentInfo intent = new ActivityIntentInfo(a);
+                if (!parseIntent(res, parser, attrs, false, intent, outError)) {
+                    return null;
+                }
+                if (intent.countActions() == 0) {
+                    Slog.w(TAG, "No actions in preferred at "
+                            + mArchiveSourcePath + " "
+                            + parser.getPositionDescription());
+                } else {
+                    if (owner.preferredActivityFilters == null) {
+                        owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
+                    }
+                    owner.preferredActivityFilters.add(intent);
+                }
             } else if (parser.getName().equals("meta-data")) {
                 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
                         outError)) == null) {
@@ -2613,7 +2625,7 @@
 
             if (parser.getName().equals("intent-filter")) {
                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
-                if (!parseIntent(res, parser, attrs, flags, intent, outError, true)) {
+                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
                     return null;
                 }
                 if (intent.countActions() == 0) {
@@ -3037,7 +3049,7 @@
 
             if (parser.getName().equals("intent-filter")) {
                 ServiceIntentInfo intent = new ServiceIntentInfo(s);
-                if (!parseIntent(res, parser, attrs, flags, intent, outError, false)) {
+                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
                     return null;
                 }
 
@@ -3234,9 +3246,8 @@
     private static final String ANDROID_RESOURCES
             = "http://schemas.android.com/apk/res/android";
 
-    private boolean parseIntent(Resources res,
-            XmlPullParser parser, AttributeSet attrs, int flags,
-            IntentInfo outInfo, String[] outError, boolean isActivity)
+    private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs,
+            boolean allowGlobs, IntentInfo outInfo, String[] outError)
             throws XmlPullParserException, IOException {
 
         TypedArray sa = res.obtainAttributes(attrs,
@@ -3327,6 +3338,10 @@
                 str = sa.getNonConfigurationString(
                         com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
                 if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "sspPattern not allowed here; ssp must be literal";
+                        return false;
+                    }
                     outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
                 }
 
@@ -3353,6 +3368,10 @@
                 str = sa.getNonConfigurationString(
                         com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
                 if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "pathPattern not allowed here; path must be literal";
+                        return false;
+                    }
                     outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
                 }
 
@@ -3414,6 +3433,8 @@
         public ArrayList<String> usesOptionalLibraries = null;
         public String[] usesLibraryFiles = null;
 
+        public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
+
         public ArrayList<String> mOriginalPackages = null;
         public String mRealPackage = null;
         public ArrayList<String> mAdoptPermissions = null;
@@ -4020,6 +4041,7 @@
         public CharSequence nonLocalizedLabel;
         public int icon;
         public int logo;
+        public int preferred;
     }
 
     public final static class ActivityIntentInfo extends IntentInfo {
diff --git a/core/java/android/hardware/photography/CameraMetadata.java b/core/java/android/hardware/photography/CameraMetadata.java
index 4633b2f..c024c05 100644
--- a/core/java/android/hardware/photography/CameraMetadata.java
+++ b/core/java/android/hardware/photography/CameraMetadata.java
@@ -16,6 +16,10 @@
 
 package android.hardware.photography;
 
+import android.hardware.photography.impl.MetadataMarshalClass;
+import android.hardware.photography.impl.MetadataMarshalRect;
+import android.hardware.photography.impl.MetadataMarshalSize;
+import android.hardware.photography.impl.MetadataMarshalString;
 import android.os.Parcelable;
 import android.os.Parcel;
 import android.util.Log;
@@ -85,6 +89,11 @@
     public <T> void set(Key<T> key, T value) {
         int tag = key.getTag();
 
+        if (value == null) {
+            writeValues(tag, null);
+            return;
+        }
+
         int nativeType = getNativeType(tag);
 
         int size = packSingle(value, null, key.mType, nativeType, /* sizeOnly */true);
@@ -265,6 +274,11 @@
     private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType,
             boolean sizeOnly) {
 
+        MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
+        if (marshaler != null) {
+            return marshaler.marshal(value, buffer, nativeType, sizeOnly);
+        }
+
         /**
          * FIXME: This doesn't actually work because getFields() returns fields in an unordered
          * manner. Although we could sort and get the data to come out correctly on the *java* side,
@@ -558,6 +572,11 @@
 
     private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) {
 
+        MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
+        if (marshaler != null) {
+            return marshaler.unmarshal(buffer, nativeType);
+        }
+
         /**
          * FIXME: This doesn't actually work because getFields() returns fields in an unordered
          * manner. Although we could sort and get the data to come out correctly on the *java* side,
@@ -611,14 +630,44 @@
         Class<?> componentType = type.getComponentType();
         Object array;
 
-        int remaining = buffer.remaining();
-        // FIXME: Assumes that the rest of the ByteBuffer is part of the array.
-        int arraySize = remaining / getTypeSize(nativeType);
+        int elementSize = getTypeSize(nativeType);
 
-        array = Array.newInstance(componentType, arraySize);
-        for (int i = 0; i < arraySize; ++i) {
-           Object elem = unpackSingle(buffer, componentType, nativeType);
-           Array.set(array, i, elem);
+        MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType);
+        if (marshaler != null) {
+            elementSize = marshaler.getNativeSize(nativeType);
+        }
+
+        if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) {
+            int remaining = buffer.remaining();
+            int arraySize = remaining / elementSize;
+
+            Log.v(TAG,
+                    String.format(
+                            "Attempting to unpack array (count = %d, element size = %d, bytes " +
+                                    "remaining = %d) for type %s",
+                            arraySize, elementSize, remaining, type));
+
+            array = Array.newInstance(componentType, arraySize);
+            for (int i = 0; i < arraySize; ++i) {
+               Object elem = unpackSingle(buffer, componentType, nativeType);
+               Array.set(array, i, elem);
+            }
+        } else {
+            // Dynamic size, use an array list.
+            ArrayList<Object> arrayList = new ArrayList<Object>();
+
+            int primitiveSize = getTypeSize(nativeType);
+            while (buffer.remaining() >= primitiveSize) {
+                Object elem = unpackSingle(buffer, componentType, nativeType);
+                arrayList.add(elem);
+            }
+
+            array = arrayList.toArray((T[]) Array.newInstance(componentType, 0));
+        }
+
+        if (buffer.remaining() != 0) {
+            Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
+                    + type);
         }
 
         return (T) array;
@@ -927,11 +976,39 @@
         return values[ordinal];
     }
 
+    static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new
+            HashMap<Class<?>, MetadataMarshalClass<?>>();
+
+    private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) {
+        sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) {
+        MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type);
+
+        if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) {
+            throw new UnsupportedOperationException("Unsupported type " + nativeType +
+                    " to be marshalled to/from a " + type);
+        }
+
+        return marshaler;
+    }
+
     /**
      * We use a class initializer to allow the native code to cache some field offsets
      */
     static {
         System.loadLibrary("media_jni");
         nativeClassInit();
+
+        Log.v(TAG, "Shall register metadata marshalers");
+
+        // load built-in marshallers
+        registerMarshaler(new MetadataMarshalRect());
+        registerMarshaler(new MetadataMarshalSize());
+        registerMarshaler(new MetadataMarshalString());
+
+        Log.v(TAG, "Registered metadata marshalers");
     }
 }
diff --git a/core/java/android/hardware/photography/CameraPropertiesKeys.java b/core/java/android/hardware/photography/CameraPropertiesKeys.java
index 55e39c2..db8ab44 100644
--- a/core/java/android/hardware/photography/CameraPropertiesKeys.java
+++ b/core/java/android/hardware/photography/CameraPropertiesKeys.java
@@ -71,8 +71,8 @@
     }
 
     public static final class Jpeg {
-        public static final Key<int[]> AVAILABLE_THUMBNAIL_SIZES =
-                new Key<int[]>("android.jpeg.availableThumbnailSizes", int[].class);
+        public static final Key<android.hardware.photography.Size[]> AVAILABLE_THUMBNAIL_SIZES =
+                new Key<android.hardware.photography.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.photography.Size[].class);
 
     }
 
@@ -90,8 +90,8 @@
                     new Key<Float>("android.lens.info.hyperfocalDistance", float.class);
             public static final Key<Float> MINIMUM_FOCUS_DISTANCE =
                     new Key<Float>("android.lens.info.minimumFocusDistance", float.class);
-            public static final Key<int[]> SHADING_MAP_SIZE =
-                    new Key<int[]>("android.lens.info.shadingMapSize", int[].class);
+            public static final Key<android.hardware.photography.Size> SHADING_MAP_SIZE =
+                    new Key<android.hardware.photography.Size>("android.lens.info.shadingMapSize", android.hardware.photography.Size.class);
         }
 
             public static final class FacingKey extends Key<Lens.FacingKey.Enum> {
@@ -161,29 +161,29 @@
                 new AvailableFormatsKey("android.scaler.availableFormats");
         public static final Key<long[]> AVAILABLE_JPEG_MIN_DURATIONS =
                 new Key<long[]>("android.scaler.availableJpegMinDurations", long[].class);
-        public static final Key<int[]> AVAILABLE_JPEG_SIZES =
-                new Key<int[]>("android.scaler.availableJpegSizes", int[].class);
+        public static final Key<android.hardware.photography.Size[]> AVAILABLE_JPEG_SIZES =
+                new Key<android.hardware.photography.Size[]>("android.scaler.availableJpegSizes", android.hardware.photography.Size[].class);
         public static final Key<Float> AVAILABLE_MAX_DIGITAL_ZOOM =
                 new Key<Float>("android.scaler.availableMaxDigitalZoom", float.class);
         public static final Key<long[]> AVAILABLE_PROCESSED_MIN_DURATIONS =
                 new Key<long[]>("android.scaler.availableProcessedMinDurations", long[].class);
-        public static final Key<int[]> AVAILABLE_PROCESSED_SIZES =
-                new Key<int[]>("android.scaler.availableProcessedSizes", int[].class);
+        public static final Key<android.hardware.photography.Size[]> AVAILABLE_PROCESSED_SIZES =
+                new Key<android.hardware.photography.Size[]>("android.scaler.availableProcessedSizes", android.hardware.photography.Size[].class);
 
     }
 
     public static final class Sensor {
         public static final class Info {
-            public static final Key<int[]> ACTIVE_ARRAY_SIZE =
-                    new Key<int[]>("android.sensor.info.activeArraySize", int[].class);
+            public static final Key<android.graphics.Rect> ACTIVE_ARRAY_SIZE =
+                    new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class);
             public static final Key<int[]> SENSITIVITY_RANGE =
                     new Key<int[]>("android.sensor.info.sensitivityRange", int[].class);
             public static final Key<long[]> EXPOSURE_TIME_RANGE =
                     new Key<long[]>("android.sensor.info.exposureTimeRange", long[].class);
             public static final Key<Long> MAX_FRAME_DURATION =
                     new Key<Long>("android.sensor.info.maxFrameDuration", long.class);
-            public static final Key<float[]> PHYSICAL_SIZE =
-                    new Key<float[]>("android.sensor.info.physicalSize", float[].class);
+            public static final Key<android.hardware.photography.Size> PHYSICAL_SIZE =
+                    new Key<android.hardware.photography.Size>("android.sensor.info.physicalSize", android.hardware.photography.Size.class);
         }
         public static final Key<Rational> BASE_GAIN_FACTOR =
                 new Key<Rational>("android.sensor.baseGainFactor", Rational.class);
diff --git a/core/java/android/hardware/photography/CaptureRequestKeys.java b/core/java/android/hardware/photography/CaptureRequestKeys.java
index d8748cf..ca6d487 100644
--- a/core/java/android/hardware/photography/CaptureRequestKeys.java
+++ b/core/java/android/hardware/photography/CaptureRequestKeys.java
@@ -93,25 +93,8 @@
                 new AeAntibandingModeKey("android.control.aeAntibandingMode");
         public static final Key<Integer> AE_EXPOSURE_COMPENSATION =
                 new Key<Integer>("android.control.aeExposureCompensation", int.class);
-
-            public static final class AeLockKey extends Key<Control.AeLockKey.Enum> {
-                public enum Enum {
-                    OFF,
-                    ON;
-                }
-
-                public static final Enum OFF = Enum.OFF;
-                public static final Enum ON = Enum.ON;
-
-                // TODO: remove requirement for constructor by making Key an interface
-                private AeLockKey(String name) {
-                    super(name, Control.AeLockKey.Enum.class);
-                }
-
-            }
-
-        public static final Key<Control.AeLockKey.Enum> AE_LOCK =
-                new AeLockKey("android.control.aeLock");
+        public static final Key<Boolean> AE_LOCK =
+                new Key<Boolean>("android.control.aeLock", boolean.class);
 
             public static final class AeModeKey extends Key<Control.AeModeKey.Enum> {
                 public enum Enum {
@@ -210,25 +193,8 @@
 
         public static final Key<Control.AfTriggerKey.Enum> AF_TRIGGER =
                 new AfTriggerKey("android.control.afTrigger");
-
-            public static final class AwbLockKey extends Key<Control.AwbLockKey.Enum> {
-                public enum Enum {
-                    OFF,
-                    ON;
-                }
-
-                public static final Enum OFF = Enum.OFF;
-                public static final Enum ON = Enum.ON;
-
-                // TODO: remove requirement for constructor by making Key an interface
-                private AwbLockKey(String name) {
-                    super(name, Control.AwbLockKey.Enum.class);
-                }
-
-            }
-
-        public static final Key<Control.AwbLockKey.Enum> AWB_LOCK =
-                new AwbLockKey("android.control.awbLock");
+        public static final Key<Boolean> AWB_LOCK =
+                new Key<Boolean>("android.control.awbLock", boolean.class);
 
             public static final class AwbModeKey extends Key<Control.AwbModeKey.Enum> {
                 public enum Enum {
@@ -415,25 +381,8 @@
 
         public static final Key<Control.SceneModeKey.Enum> SCENE_MODE =
                 new SceneModeKey("android.control.sceneMode");
-
-            public static final class VideoStabilizationModeKey extends Key<Control.VideoStabilizationModeKey.Enum> {
-                public enum Enum {
-                    OFF,
-                    ON;
-                }
-
-                public static final Enum OFF = Enum.OFF;
-                public static final Enum ON = Enum.ON;
-
-                // TODO: remove requirement for constructor by making Key an interface
-                private VideoStabilizationModeKey(String name) {
-                    super(name, Control.VideoStabilizationModeKey.Enum.class);
-                }
-
-            }
-
-        public static final Key<Control.VideoStabilizationModeKey.Enum> VIDEO_STABILIZATION_MODE =
-                new VideoStabilizationModeKey("android.control.videoStabilizationMode");
+        public static final Key<Boolean> VIDEO_STABILIZATION_MODE =
+                new Key<Boolean>("android.control.videoStabilizationMode", boolean.class);
 
     }
 
@@ -490,8 +439,8 @@
     public static final class Jpeg {
         public static final Key<double[]> GPS_COORDINATES =
                 new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
-        public static final Key<Byte> GPS_PROCESSING_METHOD =
-                new Key<Byte>("android.jpeg.gpsProcessingMethod", byte.class);
+        public static final Key<String> GPS_PROCESSING_METHOD =
+                new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
         public static final Key<Long> GPS_TIMESTAMP =
                 new Key<Long>("android.jpeg.gpsTimestamp", long.class);
         public static final Key<Integer> ORIENTATION =
@@ -500,8 +449,8 @@
                 new Key<Byte>("android.jpeg.quality", byte.class);
         public static final Key<Byte> THUMBNAIL_QUALITY =
                 new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
-        public static final Key<int[]> THUMBNAIL_SIZE =
-                new Key<int[]>("android.jpeg.thumbnailSize", int[].class);
+        public static final Key<android.hardware.photography.Size> THUMBNAIL_SIZE =
+                new Key<android.hardware.photography.Size>("android.jpeg.thumbnailSize", android.hardware.photography.Size.class);
 
     }
 
@@ -574,8 +523,8 @@
     }
 
     public static final class Scaler {
-        public static final Key<int[]> CROP_REGION =
-                new Key<int[]>("android.scaler.cropRegion", int[].class);
+        public static final Key<android.graphics.Rect> CROP_REGION =
+                new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
 
     }
 
@@ -649,54 +598,17 @@
      * @hide
      */
     public static final class Led {
-
-            /**
-             * @hide
-             */
-            public static final class TransmitKey extends Key<Led.TransmitKey.Enum> {
-                public enum Enum {
-                    OFF,
-                    ON;
-                }
-
-                public static final Enum OFF = Enum.OFF;
-                public static final Enum ON = Enum.ON;
-
-                // TODO: remove requirement for constructor by making Key an interface
-                private TransmitKey(String name) {
-                    super(name, Led.TransmitKey.Enum.class);
-                }
-
-            }
-
         /**
          * @hide
          */
-        public static final Key<Led.TransmitKey.Enum> TRANSMIT =
-                new TransmitKey("android.led.transmit");
+        public static final Key<Boolean> TRANSMIT =
+                new Key<Boolean>("android.led.transmit", boolean.class);
 
     }
 
     public static final class BlackLevel {
-
-            public static final class LockKey extends Key<BlackLevel.LockKey.Enum> {
-                public enum Enum {
-                    OFF,
-                    ON;
-                }
-
-                public static final Enum OFF = Enum.OFF;
-                public static final Enum ON = Enum.ON;
-
-                // TODO: remove requirement for constructor by making Key an interface
-                private LockKey(String name) {
-                    super(name, BlackLevel.LockKey.Enum.class);
-                }
-
-            }
-
-        public static final Key<BlackLevel.LockKey.Enum> LOCK =
-                new LockKey("android.blackLevel.lock");
+        public static final Key<Boolean> LOCK =
+                new Key<Boolean>("android.blackLevel.lock", boolean.class);
 
     }
 
diff --git a/core/java/android/hardware/photography/CaptureResultKeys.java b/core/java/android/hardware/photography/CaptureResultKeys.java
index de305b0..4931564 100644
--- a/core/java/android/hardware/photography/CaptureResultKeys.java
+++ b/core/java/android/hardware/photography/CaptureResultKeys.java
@@ -300,8 +300,8 @@
     public static final class Jpeg {
         public static final Key<double[]> GPS_COORDINATES =
                 new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
-        public static final Key<Byte> GPS_PROCESSING_METHOD =
-                new Key<Byte>("android.jpeg.gpsProcessingMethod", byte.class);
+        public static final Key<String> GPS_PROCESSING_METHOD =
+                new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
         public static final Key<Long> GPS_TIMESTAMP =
                 new Key<Long>("android.jpeg.gpsTimestamp", long.class);
         public static final Key<Integer> ORIENTATION =
@@ -310,8 +310,8 @@
                 new Key<Byte>("android.jpeg.quality", byte.class);
         public static final Key<Byte> THUMBNAIL_QUALITY =
                 new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
-        public static final Key<int[]> THUMBNAIL_SIZE =
-                new Key<int[]>("android.jpeg.thumbnailSize", int[].class);
+        public static final Key<android.hardware.photography.Size> THUMBNAIL_SIZE =
+                new Key<android.hardware.photography.Size>("android.jpeg.thumbnailSize", android.hardware.photography.Size.class);
 
     }
 
@@ -402,8 +402,8 @@
     }
 
     public static final class Scaler {
-        public static final Key<int[]> CROP_REGION =
-                new Key<int[]>("android.scaler.cropRegion", int[].class);
+        public static final Key<android.graphics.Rect> CROP_REGION =
+                new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
 
     }
 
@@ -445,8 +445,8 @@
                 new Key<int[]>("android.statistics.faceIds", int[].class);
         public static final Key<int[]> FACE_LANDMARKS =
                 new Key<int[]>("android.statistics.faceLandmarks", int[].class);
-        public static final Key<int[]> FACE_RECTANGLES =
-                new Key<int[]>("android.statistics.faceRectangles", int[].class);
+        public static final Key<android.graphics.Rect[]> FACE_RECTANGLES =
+                new Key<android.graphics.Rect[]>("android.statistics.faceRectangles", android.graphics.Rect[].class);
         public static final Key<byte[]> FACE_SCORES =
                 new Key<byte[]>("android.statistics.faceScores", byte[].class);
         public static final Key<float[]> LENS_SHADING_MAP =
@@ -514,54 +514,17 @@
      * @hide
      */
     public static final class Led {
-
-            /**
-             * @hide
-             */
-            public static final class TransmitKey extends Key<Led.TransmitKey.Enum> {
-                public enum Enum {
-                    OFF,
-                    ON;
-                }
-
-                public static final Enum OFF = Enum.OFF;
-                public static final Enum ON = Enum.ON;
-
-                // TODO: remove requirement for constructor by making Key an interface
-                private TransmitKey(String name) {
-                    super(name, Led.TransmitKey.Enum.class);
-                }
-
-            }
-
         /**
          * @hide
          */
-        public static final Key<Led.TransmitKey.Enum> TRANSMIT =
-                new TransmitKey("android.led.transmit");
+        public static final Key<Boolean> TRANSMIT =
+                new Key<Boolean>("android.led.transmit", boolean.class);
 
     }
 
     public static final class BlackLevel {
-
-            public static final class LockKey extends Key<BlackLevel.LockKey.Enum> {
-                public enum Enum {
-                    OFF,
-                    ON;
-                }
-
-                public static final Enum OFF = Enum.OFF;
-                public static final Enum ON = Enum.ON;
-
-                // TODO: remove requirement for constructor by making Key an interface
-                private LockKey(String name) {
-                    super(name, BlackLevel.LockKey.Enum.class);
-                }
-
-            }
-
-        public static final Key<BlackLevel.LockKey.Enum> LOCK =
-                new LockKey("android.blackLevel.lock");
+        public static final Key<Boolean> LOCK =
+                new Key<Boolean>("android.blackLevel.lock", boolean.class);
 
     }
 
diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalClass.java b/core/java/android/hardware/photography/impl/MetadataMarshalClass.java
new file mode 100644
index 0000000..a70784d
--- /dev/null
+++ b/core/java/android/hardware/photography/impl/MetadataMarshalClass.java
@@ -0,0 +1,67 @@
+/*
+ * 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.photography.impl;
+
+import java.nio.ByteBuffer;
+
+public interface MetadataMarshalClass<T> {
+
+    /**
+     * Marshal the specified object instance (value) into a byte buffer.
+     *
+     * @param value the value of type T that we wish to write into the byte buffer
+     * @param buffer the byte buffer into which the marshalled object will be written
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
+     *        Guaranteed to be one for which isNativeTypeSupported returns true.
+     * @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only.
+     * @return the size that needs to be written to the byte buffer
+     */
+    int marshal(T value, ByteBuffer buffer, int nativeType, boolean sizeOnly);
+
+    /**
+     * Unmarshal a new object instance from the byte buffer.
+     * @param buffer the byte buffer, from which we will read the object
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
+     *        Guaranteed to be one for which isNativeTypeSupported returns true.
+     * @return a new instance of type T read from the byte buffer
+     */
+    T unmarshal(ByteBuffer buffer, int nativeType);
+
+    Class<T> getMarshalingClass();
+
+    /**
+     * Determines whether or not this marshaller supports this native type. Most marshallers
+     * will are likely to only support one type.
+     *
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}
+     * @return true if it supports, false otherwise
+     */
+    boolean isNativeTypeSupported(int nativeType);
+
+    public static int NATIVE_SIZE_DYNAMIC = -1;
+
+    /**
+     * How many bytes T will take up if marshalled to/from nativeType
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}
+     * @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic
+     */
+    int getNativeSize(int nativeType);
+}
diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalRect.java b/core/java/android/hardware/photography/impl/MetadataMarshalRect.java
new file mode 100644
index 0000000..d6636ac
--- /dev/null
+++ b/core/java/android/hardware/photography/impl/MetadataMarshalRect.java
@@ -0,0 +1,68 @@
+/*
+ * 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.photography.impl;
+
+import android.graphics.Rect;
+import android.hardware.photography.CameraMetadata;
+
+import java.nio.ByteBuffer;
+
+public class MetadataMarshalRect implements MetadataMarshalClass<Rect> {
+    private static final int SIZE = 16;
+
+    @Override
+    public int marshal(Rect value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
+        if (sizeOnly) {
+            return SIZE;
+        }
+
+        buffer.putInt(value.left);
+        buffer.putInt(value.top);
+        buffer.putInt(value.width());
+        buffer.putInt(value.height());
+
+        return SIZE;
+    }
+
+    @Override
+    public Rect unmarshal(ByteBuffer buffer, int nativeType) {
+
+        int left = buffer.getInt();
+        int top = buffer.getInt();
+        int width = buffer.getInt();
+        int height = buffer.getInt();
+
+        int right = left + width;
+        int bottom = top + height;
+
+        return new Rect(left, top, right, bottom);
+    }
+
+    @Override
+    public Class<Rect> getMarshalingClass() {
+        return Rect.class;
+    }
+
+    @Override
+    public boolean isNativeTypeSupported(int nativeType) {
+        return nativeType == CameraMetadata.TYPE_INT32;
+    }
+
+    @Override
+    public int getNativeSize(int nativeType) {
+        return SIZE;
+    }
+}
diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalSize.java b/core/java/android/hardware/photography/impl/MetadataMarshalSize.java
new file mode 100644
index 0000000..430219c
--- /dev/null
+++ b/core/java/android/hardware/photography/impl/MetadataMarshalSize.java
@@ -0,0 +1,61 @@
+/*
+ * 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.photography.impl;
+
+import android.hardware.photography.CameraMetadata;
+import android.hardware.photography.Size;
+
+import java.nio.ByteBuffer;
+
+public class MetadataMarshalSize implements MetadataMarshalClass<Size> {
+
+    private static final int SIZE = 8;
+
+    @Override
+    public int marshal(Size value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
+        if (sizeOnly) {
+            return SIZE;
+        }
+
+        buffer.putInt(value.getWidth());
+        buffer.putInt(value.getHeight());
+
+        return SIZE;
+    }
+
+    @Override
+    public Size unmarshal(ByteBuffer buffer, int nativeType) {
+        int width = buffer.getInt();
+        int height = buffer.getInt();
+
+        return new Size(width, height);
+    }
+
+    @Override
+    public Class<Size> getMarshalingClass() {
+        return Size.class;
+    }
+
+    @Override
+    public boolean isNativeTypeSupported(int nativeType) {
+        return nativeType == CameraMetadata.TYPE_INT32;
+    }
+
+    @Override
+    public int getNativeSize(int nativeType) {
+        return SIZE;
+    }
+}
diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalString.java b/core/java/android/hardware/photography/impl/MetadataMarshalString.java
new file mode 100644
index 0000000..81123ee
--- /dev/null
+++ b/core/java/android/hardware/photography/impl/MetadataMarshalString.java
@@ -0,0 +1,81 @@
+/*
+ * 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.photography.impl;
+
+import android.hardware.photography.CameraMetadata;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+public class MetadataMarshalString implements MetadataMarshalClass<String> {
+
+    private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
+
+    @Override
+    public int marshal(String value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
+        byte[] arr = value.getBytes(UTF8_CHARSET);
+
+        if (!sizeOnly) {
+            buffer.put(arr);
+            buffer.put((byte)0); // metadata strings are NULL-terminated
+        }
+
+        return arr.length + 1;
+    }
+
+    @Override
+    public String unmarshal(ByteBuffer buffer, int nativeType) {
+
+        buffer.mark(); // save the current position
+
+        boolean foundNull = false;
+        int stringLength = 0;
+        while (buffer.hasRemaining()) {
+            if (buffer.get() == (byte)0) {
+                foundNull = true;
+                break;
+            }
+
+            stringLength++;
+        }
+        if (!foundNull) {
+            throw new IllegalArgumentException("Strings must be null-terminated");
+        }
+
+        buffer.reset(); // go back to the previously marked position
+
+        byte[] strBytes = new byte[stringLength + 1];
+        buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character
+
+        // not including null character
+        return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET);
+    }
+
+    @Override
+    public Class<String> getMarshalingClass() {
+        return String.class;
+    }
+
+    @Override
+    public boolean isNativeTypeSupported(int nativeType) {
+        return nativeType == CameraMetadata.TYPE_BYTE;
+    }
+
+    @Override
+    public int getNativeSize(int nativeType) {
+        return NATIVE_SIZE_DYNAMIC;
+    }
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 04ab0a5..8bbe6c8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -480,6 +480,22 @@
     }
 
     /**
+     * Checks if the given network type should be exempt from VPN routing rules
+     *
+     * @hide
+     */
+    public static boolean isNetworkTypeExempt(int networkType) {
+        switch (networkType) {
+            case TYPE_MOBILE_MMS:
+            case TYPE_MOBILE_SUPL:
+            case TYPE_MOBILE_HIPRI:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
      * Specifies the preferred network type.  When the device has more
      * than one type available the preferred network type will be used.
      * Note that this made sense when we only had 2 network types,
@@ -1373,4 +1389,16 @@
         }
         return timeOutMs;
     }
+
+    /**
+     * Get the carrier provisioning url.
+     * {@hide}
+     */
+    public String getMobileProvisioningUrl() {
+        try {
+            return mService.getMobileProvisioningUrl();
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d537b32..b0f7fc6 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -124,6 +124,8 @@
 
     ParcelFileDescriptor establishVpn(in VpnConfig config);
 
+    VpnConfig getVpnConfig();
+
     void startLegacyVpn(in VpnProfile profile);
 
     LegacyVpnInfo getLegacyVpnInfo();
@@ -137,4 +139,6 @@
     int findConnectionTypeForIface(in String iface);
 
     int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver);
+
+    String getMobileProvisioningUrl();
 }
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
new file mode 100644
index 0000000..e52c0c3
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -0,0 +1,222 @@
+package android.nfc.cardemulation;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * <p>A convenience class that can be extended to implement
+ * a service that processes ISO7816-4 commands on top of
+ * the ISO14443-4 / IsoDep protocol (T=CL).
+ *
+ * <p>To tell the platform which ISO7816 application ID (AIDs)
+ * are implemented by this service, a {@link #SERVICE_META_DATA}
+ * entry must be included in the declaration of the service. An
+ * example of such a service declaration is shown below:
+ * <pre> &lt;service android:name=".MyHostApduService"&gt;
+ *     &lt;intent-filter&gt;
+ *         &lt;action android:name="android.nfc.HostApduService"/&gt;
+ *     &lt;/intent-filter&gt;
+ *     &lt;meta-data android:name="android.nfc.HostApduService" android:resource="@xml/apduservice.xml"/&gt;
+ * &lt;/service&gt;</pre>
+ * <p>For more details refer to {@link #SERVICE_META_DATA},
+ * <code>&lt;{@link android.R.styleable#ApduService apdu-service}&gt;</code> and
+ * <code>&lt;{@link android.R.styleable#AidFilter aid-filter}&gt;</code>.
+ * <p class="note">The Android platform currently only supports a single
+ * logical channel.
+ */
+public abstract class HostApduService extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.nfc.HostApduService";
+
+    /**
+     * The name of the meta-data element that contains
+     * more information about this service.
+     */
+    public static final String SERVICE_META_DATA = "android.nfc.HostApduService";
+
+    /**
+     * Reason for {@link #onDeactivated(int)}.
+     * Indicates deactivation was due to the NFC link
+     * being lost.
+     */
+    public static final int DEACTIVATION_LINK_LOSS = 0;
+
+    /**
+     * Reason for {@link #onDeactivated(int)}.
+     *
+     * <p>Indicates deactivation was due to a different AID
+     * being selected (which implicitly deselects the AID
+     * currently active on the logical channel).
+     *
+     * <p>Note that this next AID may still be resolved to this
+     * service, in which case {@link #processCommandApdu(byte[], int)}
+     * will be called again.
+     */
+    public static final int DEACTIVATION_DESELECTED = 1;
+
+    static final String TAG = "ApduService";
+
+    /**
+     * MSG_COMMAND_APDU is sent by NfcService when
+     * a 7816-4 command APDU has been received.
+     *
+     * @hide
+     */
+    public static final int MSG_COMMAND_APDU = 0;
+
+    /**
+     * MSG_RESPONSE_APDU is sent to NfcService to send
+     * a response APDU back to the remote device.
+     *
+     * @hide
+     */
+    public static final int MSG_RESPONSE_APDU = 1;
+
+    /**
+     * MSG_DEACTIVATED is sent by NfcService when
+     * the current session is finished; either because
+     * another AID was selected that resolved to
+     * another service, or because the NFC link
+     * was deactivated.
+     *
+     * @hide
+     */
+    public static final int MSG_DEACTIVATED = 2;
+
+    /**
+     * @hide
+     */
+    public static final String KEY_DATA = "data";
+
+    /**
+     * Messenger interface to NfcService for sending responses.
+     * Only accessed on main thread by the message handler.
+     */
+    Messenger mNfcService = null;
+
+    final Messenger mMessenger = new Messenger(new MsgHandler());
+
+    final class MsgHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MSG_COMMAND_APDU:
+                Bundle dataBundle = msg.getData();
+                if (dataBundle == null) {
+                    return;
+                }
+                if (mNfcService == null) mNfcService = msg.replyTo;
+
+                byte[] apdu = dataBundle.getByteArray(KEY_DATA);
+                if (apdu != null) {
+                    byte[] responseApdu = processCommandApdu(apdu, 0);
+                    if (responseApdu != null) {
+                        if (mNfcService == null) {
+                            Log.e(TAG, "Response not sent; service was deactivated.");
+                            return;
+                        }
+                        Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU);
+                        Bundle responseBundle = new Bundle();
+                        responseBundle.putByteArray(KEY_DATA, responseApdu);
+                        responseMsg.setData(responseBundle);
+                        try {
+                            mNfcService.send(responseMsg);
+                        } catch (RemoteException e) {
+                            Log.e("TAG", "Response not sent; RemoteException calling into " +
+                                    "NfcService.");
+                        }
+                    }
+                } else {
+                    Log.e(TAG, "Received MSG_COMMAND_APDU without data.");
+                }
+                break;
+            case MSG_RESPONSE_APDU:
+                if (mNfcService == null) {
+                    Log.e(TAG, "Response not sent; service was deactivated.");
+                    return;
+                }
+                try {
+                    mNfcService.send(msg);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException calling into NfcService.");
+                }
+                break;
+            case MSG_DEACTIVATED:
+                // Make sure we won't call into NfcService again
+                mNfcService = null;
+                onDeactivated(msg.arg1);
+                break;
+            default:
+                super.handleMessage(msg);
+            }
+        }
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+
+    /**
+     * Sends a response APDU back to the remote device.
+     *
+     * <p>Note: this method may be called from any thread and will not block.
+     * @param responseApdu A byte-array containing the reponse APDU.
+     */
+    public final void sendResponseApdu(byte[] responseApdu) {
+        Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU);
+        Bundle dataBundle = new Bundle();
+        dataBundle.putByteArray(KEY_DATA, responseApdu);
+        responseMsg.setData(dataBundle);
+        try {
+            mMessenger.send(responseMsg);
+        } catch (RemoteException e) {
+            Log.e("TAG", "Local messenger has died.");
+        }
+    }
+
+    /**
+     * <p>This method will be called when a command APDU has been received
+     * from a remote device. A response APDU can be provided directly
+     * by returning a byte-array in this method. Note that in general
+     * response APDUs must be sent as quickly as possible, given the fact
+     * that the user is likely holding his device over an NFC reader
+     * when this method is called.
+     *
+     * <p class="note">If there are multiple services that have registered for the same
+     * AIDs in their meta-data entry, you will only get called if the user has
+     * explicitly selected your service, either as a default or just for the next tap.
+     *
+     * <p class="note">This method is running on the main thread of your application.
+     * If you cannot return a response APDU immediately, return null
+     * and use the {@link #sendResponseApdu(byte[])} method later.
+     *
+     * @param commandApdu
+     * @param flags
+     * @return a byte-array containing the response APDU, or null if no
+     *         response APDU can be sent at this point.
+     */
+    public abstract byte[] processCommandApdu(byte[] commandApdu, int flags);
+
+    /**
+     * This method will be called in two possible scenarios:
+     * <li>The NFC link has been deactivated or lost
+     * <li>A different AID has been selected and was resolved to a different
+     *     service component
+     * @param reason Either {@link #DEACTIVATION_LINK_LOSS} or {@link #DEACTIVATION_DESELECTED}
+     */
+    public abstract void onDeactivated(int reason);
+}
diff --git a/core/java/android/nfc/cardemulation/SeApduService.java b/core/java/android/nfc/cardemulation/SeApduService.java
new file mode 100644
index 0000000..78f8312
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/SeApduService.java
@@ -0,0 +1,111 @@
+package android.nfc.cardemulation;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+
+/**
+ * <p>A convenience class that can be extended to implement
+ * a service that registers and deals with events for
+ * ISO7814-4 AIDs that reside on an embedded secure element
+ * or UICC.
+ *
+ * <p>To tell the platform which ISO7816 application ID (AIDs)
+ * are present on the Secure Element and handled by this service,
+ * a {@link #SERVICE_META_DATA} entry must be included in the declaration
+ * of the service. An example of such a service declaration is shown below:
+ * <pre> &lt;service android:name=".MySeApduService"&gt;
+ *     &lt;intent-filter&gt;
+ *         &lt;action android:name="android.nfc.SeApduService"/&gt;
+ *     &lt;/intent-filter&gt;
+ *     &lt;meta-data android:name="android.nfc.SeApduService" android:resource="@xml/apduservice.xml"/&gt;
+ * &lt;/service&gt;</pre>
+ * <p>For more details refer to {@link #SERVICE_META_DATA},
+ * <code>&lt;{@link android.R.styleable#ApduService apdu-service}&gt;</code> and
+ * <code>&lt;{@link android.R.styleable#AidFilter aid-filter}&gt;</code>.
+ */
+public abstract class SeApduService extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.nfc.SeApduService";
+
+    /**
+     * The name of the meta-data element that contains
+     * more information about this service.
+     */
+    public static final String SERVICE_META_DATA = "android.nfc.SeApduService";
+
+    /**
+     * @hide
+     */
+    public static final int MSG_AID_SELECTED = 0;
+
+    /**
+     * @hide
+     */
+    public static final int MSG_HCI_TRANSACTION_EVT = 1;
+
+    /**
+     * @hide
+     */
+    public static final String KEY_AID = "aid";
+
+    /**
+     * @hide
+     */
+    public static final String KEY_PARAMETERS = "parameters";
+
+    final Messenger mMessenger = new Messenger(new MsgHandler());
+
+    final class MsgHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what){
+                case MSG_AID_SELECTED: {
+                    Bundle dataBundle = msg.getData();
+                    byte[] aid = dataBundle.getByteArray(KEY_AID);
+                    onAidSelected(aid);
+                    break;
+                }
+                case MSG_HCI_TRANSACTION_EVT: {
+                    Bundle dataBundle = msg.getData();
+                    byte[] aid = dataBundle.getByteArray(KEY_AID);
+                    byte[] parameters = dataBundle.getByteArray(KEY_PARAMETERS);
+                    onHciTransactionEvent(aid, parameters);
+                    break;
+                }
+            }
+        }
+    };
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+
+    /**
+     * This method is called when an AID that has been registered
+     * in the manifest of this service has been selected on a
+     * eSE/UICC.
+     * @param aid The AID that has been selected
+     */
+    public abstract void onAidSelected(byte[] aid);
+
+    /**
+     * This method is called when a HCI transaction event has
+     * been received for an AID that has been registered
+     * in the manifest of this service.
+     * @param aid The AID of the application that generated the event
+     * @param parameters Parameters according to ETSI-TS 102 622
+     */
+    public abstract void onHciTransactionEvent(byte[] aid, byte[] parameters);
+}
\ No newline at end of file
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 48eb8cc..f474504 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -217,6 +217,7 @@
         if (mMap == null) {
             mMap = new ArrayMap<String, Object>(N);
         } else {
+            mMap.erase();
             mMap.ensureCapacity(N);
         }
         mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 51c367a..ed9620f 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -19,6 +19,7 @@
 
 import android.net.InterfaceConfiguration;
 import android.net.INetworkManagementEventObserver;
+import android.net.LinkAddress;
 import android.net.NetworkStats;
 import android.net.RouteInfo;
 import android.net.wifi.WifiConfiguration;
@@ -388,6 +389,17 @@
     void clearMarkedForwardingRoute(String iface, in RouteInfo route);
 
     /**
+     * Exempts {@code host} from the routing set up by {@link setMarkedForwardingRoute}
+     * All connects to {@code host} will use the global routing table
+     */
+    void setHostExemption(in LinkAddress host);
+
+    /**
+     * Clears an exemption set by {@link setHostExemption}
+     */
+    void clearHostExemption(in LinkAddress host);
+
+    /**
      * Set a process (pid) to use the name servers associated with the specified interface.
      */
     void setDnsInterfaceForPid(String iface, int pid);
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 7589a5a..bd2d9ac 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -49,4 +49,5 @@
     boolean changeRestrictionsPin(in String newPin);
     int checkRestrictionsPin(in String pin);
     boolean hasRestrictionsPin();
+    void removeRestrictions();
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c33a28a..83426ae 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -140,6 +140,16 @@
      */
     public static final String DISALLOW_REMOVE_USER = "no_remove_user";
 
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from setting app restrictions
+     * via a restrictions PIN. The default is <code>false</code>. If app restrictions have already
+     * been set up, then this user restriction cannot be set to true.
+     * <p/>
+     * Type: Boolean
+     * @see #hasRestrictionsPin()
+     */
+    public static final String DISALLOW_APP_RESTRICTIONS = "no_app_restrictions";
+
     /** @hide */
     public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
     /** @hide */
@@ -678,4 +688,13 @@
         }
         return false;
     }
+
+    /** @hide */
+    public void removeRestrictions() {
+        try {
+            mService.removeRestrictions();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not change restrictions pin");
+        }
+    }
 }
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index f44cbe4..9edf112 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -16,13 +16,13 @@
 
 package android.preference;
 
-
 import android.app.AlertDialog.Builder;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 
 /**
@@ -41,6 +41,7 @@
     private String mValue;
     private String mSummary;
     private int mClickedDialogEntryIndex;
+    private boolean mValueSet;
     
     public ListPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -130,9 +131,16 @@
      * @param value The value to set for the key.
      */
     public void setValue(String value) {
-        mValue = value;
-        
-        persistString(value);
+        // Always persist/notify the first time.
+        final boolean changed = !TextUtils.equals(mValue, value);
+        if (changed || !mValueSet) {
+            mValue = value;
+            mValueSet = true;
+            persistString(value);
+            if (changed) {
+                notifyChanged();
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index caf55d7..dc683a6 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -25,11 +25,14 @@
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.Settings;
 import android.provider.Settings.System;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.SeekBar;
@@ -115,7 +118,7 @@
 
     public void onActivityStop() {
         if (mSeekBarVolumizer != null) {
-            mSeekBarVolumizer.stopSample();
+            mSeekBarVolumizer.postStopSample();
         }
     }
 
@@ -220,10 +223,10 @@
     /**
      * Turns a {@link SeekBar} into a volume control.
      */
-    public class SeekBarVolumizer implements OnSeekBarChangeListener, Runnable {
+    public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback {
 
         private Context mContext;
-        private Handler mHandler = new Handler();
+        private Handler mHandler;
 
         private AudioManager mAudioManager;
         private int mStreamType;
@@ -234,6 +237,11 @@
         private SeekBar mSeekBar;
         private int mVolumeBeforeMute = -1;
 
+        private static final int MSG_SET_STREAM_VOLUME = 0;
+        private static final int MSG_START_SAMPLE = 1;
+        private static final int MSG_STOP_SAMPLE = 2;
+        private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
+
         private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
             @Override
             public void onChange(boolean selfChange) {
@@ -255,6 +263,10 @@
             mStreamType = streamType;
             mSeekBar = seekBar;
 
+            HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
+            thread.start();
+            mHandler = new Handler(thread.getLooper(), this);
+
             initSeekBar(seekBar, defaultUri);
         }
 
@@ -285,8 +297,54 @@
             }
         }
 
+        @Override
+        public boolean handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_STREAM_VOLUME:
+                    mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
+                    break;
+                case MSG_START_SAMPLE:
+                    onStartSample();
+                    break;
+                case MSG_STOP_SAMPLE:
+                    onStopSample();
+                    break;
+                default:
+                    Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what);
+            }
+            return true;
+        }
+
+        private void postStartSample() {
+            mHandler.removeMessages(MSG_START_SAMPLE);
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
+                    isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
+        }
+
+        private void onStartSample() {
+            if (!isSamplePlaying()) {
+                onSampleStarting(this);
+                if (mRingtone != null) {
+                    mRingtone.play();
+                }
+            }
+        }
+
+        private void postStopSample() {
+            // remove pending delayed start messages
+            mHandler.removeMessages(MSG_START_SAMPLE);
+            mHandler.removeMessages(MSG_STOP_SAMPLE);
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_SAMPLE));
+        }
+
+        private void onStopSample() {
+            if (mRingtone != null) {
+                mRingtone.stop();
+            }
+        }
+
         public void stop() {
-            stopSample();
+            postStopSample();
             mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
             mSeekBar.setOnSeekBarChangeListener(null);
         }
@@ -307,21 +365,15 @@
         void postSetVolume(int progress) {
             // Do the volume changing separately to give responsive UI
             mLastProgress = progress;
-            mHandler.removeCallbacks(this);
-            mHandler.post(this);
+            mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME));
         }
 
         public void onStartTrackingTouch(SeekBar seekBar) {
         }
 
         public void onStopTrackingTouch(SeekBar seekBar) {
-            if (!isSamplePlaying()) {
-                startSample();
-            }
-        }
-
-        public void run() {
-            mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
+            postStartSample();
         }
 
         public boolean isSamplePlaying() {
@@ -329,16 +381,11 @@
         }
 
         public void startSample() {
-            onSampleStarting(this);
-            if (mRingtone != null) {
-                mRingtone.play();
-            }
+            postStartSample();
         }
 
         public void stopSample() {
-            if (mRingtone != null) {
-                mRingtone.stop();
-            }
+            postStopSample();
         }
 
         public SeekBar getSeekBar() {
@@ -347,23 +394,21 @@
 
         public void changeVolumeBy(int amount) {
             mSeekBar.incrementProgressBy(amount);
-            if (!isSamplePlaying()) {
-                startSample();
-            }
             postSetVolume(mSeekBar.getProgress());
+            postStartSample();
             mVolumeBeforeMute = -1;
         }
 
         public void muteVolume() {
             if (mVolumeBeforeMute != -1) {
                 mSeekBar.setProgress(mVolumeBeforeMute);
-                startSample();
                 postSetVolume(mVolumeBeforeMute);
+                postStartSample();
                 mVolumeBeforeMute = -1;
             } else {
                 mVolumeBeforeMute = mSeekBar.getProgress();
                 mSeekBar.setProgress(0);
-                stopSample();
+                postStopSample();
                 postSetVolume(0);
             }
         }
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index 60e6229..9257a04 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -42,8 +42,10 @@
      * @throws IllegalArgumentException If start is less than zero.
      * @throws IllegalArgumentException If end is less than zero.
      * @throws IllegalArgumentException If start greater than end.
+     *
+     * @hide
      */
-    PageRange(int start, int end) {
+    public PageRange(int start, int end) {
         if (start < 0) {
             throw new IllegalArgumentException("start cannot be less than zero.");
         }
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 2a27a32..87d75c0 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -384,6 +384,22 @@
     }
 
     /**
+     * @hide
+     */
+    public void copyFrom(PrintAttributes other) {
+        mMediaSize = other.mMediaSize;
+        mResolution = other.mResolution;
+        mMargins = other.mMargins;
+        mInputTray = other.mInputTray;
+        mOutputTray = other.mOutputTray;
+        mDuplexMode = other.mDuplexMode;
+        mColorMode = other.mColorMode;
+        mFittingMode = other.mFittingMode;
+        mOrientation = other.mOrientation;
+        mCopies = other.mCopies;
+    }
+
+    /**
      * This class specifies a supported media size.
      */
     public static final class MediaSize {
@@ -1007,7 +1023,7 @@
          *
          * @return The human readable label.
          */
-        public CharSequence getLabel(PackageManager packageManager) {
+        public CharSequence getLabel() {
             return mLabel;
         }
 
@@ -1203,7 +1219,7 @@
          *
          * @return The human readable label.
          */
-        public CharSequence getLabel(PackageManager packageManager) {
+        public CharSequence getLabel() {
             return mLabel;
         }
 
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index 7731deb..7d42b3a 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -110,6 +110,16 @@
         parcel.writeInt(mContentType);
     }
 
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("PrintDocumentInfo{");
+        builder.append("pageCount: ").append(mPageCount);
+        builder.append(", contentType: ").append(mContentType);
+        builder.append("}");
+        return builder.toString();
+    }
+
     /**
      * Builder for creating an {@link PrintDocumentInfo}.
      */
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 6e613bc..97384d9 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -35,11 +35,20 @@
     public static final int STATE_ANY = -1;
 
     /**
+     * Constant for matching any print job state.
+     *
+     * @hide
+     */
+    public static final int STATE_ANY_VISIBLE_TO_CLIENTS = -2;
+
+    /**
      * Print job state: The print job is being created but not yet
      * ready to be printed.
      * <p>
      * Next valid states: {@link #STATE_QUEUED}
      * </p>
+     *
+     * @hide
      */
     public static final int STATE_CREATED = 1;
 
@@ -132,6 +141,7 @@
         mState = other.mState;
         mAppId = other.mAppId;
         mUserId = other.mUserId;
+        mTag = other.mTag;
         mAttributes = other.mAttributes;
         mDocumentInfo = other.mDocumentInfo;
     }
@@ -143,6 +153,7 @@
         mState = parcel.readInt();
         mAppId = parcel.readInt();
         mUserId = parcel.readInt();
+        mTag = parcel.readString();
         if (parcel.readInt() == 1) {
             mPageRanges = (PageRange[]) parcel.readParcelableArray(null);
         }
@@ -373,6 +384,7 @@
         parcel.writeInt(mState);
         parcel.writeInt(mAppId);
         parcel.writeInt(mUserId);
+        parcel.writeString(mTag);
         if (mPageRanges != null) {
             parcel.writeInt(1);
             parcel.writeParcelableArray(mPageRanges, flags);
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 58f45fa..f9f53f6 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.print.PrintDocumentAdapter.LayoutResultCallback;
 import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.os.SomeArgs;
@@ -184,6 +185,9 @@
      */
     public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
             PrintAttributes attributes) {
+        if (TextUtils.isEmpty(printJobName)) {
+            throw new IllegalArgumentException("priintJobName cannot be empty");
+        }
         PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(documentAdapter,
                 mContext.getMainLooper());
         try {
diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java
index 8a3148c..e884026 100644
--- a/core/java/android/print/PrinterId.java
+++ b/core/java/android/print/PrinterId.java
@@ -125,26 +125,6 @@
         return builder.toString();
     }
 
-    /**
-     * @hide
-     */
-    public String flattenToString() {
-        return mServiceComponentName.flattenToString() + ":" + mLocalId;
-    }
-
-    /**
-     * @hide
-     */
-    public static PrinterId unflattenFromString(String string) {
-        String[] split = string.split(":");
-        if (split.length != 2) {
-            throw new IllegalArgumentException("Not well-formed printer id:" + string);
-        }
-        ComponentName component = ComponentName.unflattenFromString(split[0]);
-        String localId = String.valueOf(split[1]);
-        return new PrinterId(component, localId);
-    }
-
     public static final Parcelable.Creator<PrinterId> CREATOR =
             new Creator<PrinterId>() {
         @Override
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 820c2d8..dde31d2 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -245,13 +245,10 @@
      * @see #removeDiscoveredPrinters(List)
      * @see #onStartPrinterDiscovery()
      * @see #onStopPrinterDiscovery()
-     *
-     * @throws IllegalStateException If this service is not connected.
      */
     public final void addDiscoveredPrinters(List<PrinterInfo> printers) {
         final IPrinterDiscoveryObserver observer;
         synchronized (mLock) {
-            throwIfNotConnectedLocked();
             observer = mDiscoveryObserver;
         }
         if (observer != null) {
@@ -284,13 +281,10 @@
      * @see #addDiscoveredPrinters(List)
      * @see #onStartPrinterDiscovery()
      * @see #onStopPrinterDiscovery()
-     *
-     * @throws IllegalStateException If this service is not connected.
      */
     public final void removeDiscoveredPrinters(List<PrinterId> printerIds) {
         final IPrinterDiscoveryObserver observer;
         synchronized (mLock) {
-            throwIfNotConnectedLocked();
             observer = mDiscoveryObserver;
         }
         if (observer != null) {
@@ -334,13 +328,10 @@
      * Gets the print jobs for the printers managed by this service.
      *
      * @return The print jobs.
-     *
-     * @throws IllegalStateException If this service is not connected.
      */
     public final List<PrintJob> getPrintJobs() {
         final IPrintServiceClient client;
         synchronized (mLock) {
-            throwIfNotConnectedLocked();
             client = mClient;
         }
         if (client == null) {
@@ -410,12 +401,6 @@
         };
     }
 
-    private void throwIfNotConnectedLocked() {
-        if (mClient == null) {
-            throw new IllegalStateException("Print serivice not connected");
-        }
-    }
-
     private final class MyHandler extends Handler {
         public static final int MESSAGE_START_PRINTER_DISCOVERY = 1;
         public static final int MESSAGE_STOP_PRINTER_DISCOVERY = 2;
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 51014c8..22f62d70 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -247,6 +247,20 @@
     }
 
     /**
+     * @hide
+     * Like {@link #clear}, but doesn't reduce the capacity of the ArrayMap.
+     */
+    public void erase() {
+        if (mSize > 0) {
+            final int N = mSize<<1;
+            final Object[] array = mArray;
+            for (int i=0; i<N; i++) {
+                array[i] = null;
+            }
+        }
+    }
+
+    /**
      * Ensure the array map can hold at least <var>minimumCapacity</var>
      * items.
      */
@@ -421,8 +435,13 @@
             throw new IllegalStateException("Array is full");
         }
         if (index > 0 && mHashes[index-1] > hash) {
-            throw new IllegalArgumentException("New hash " + hash
-                    + " is before end of array hash " + mHashes[index-1]);
+            RuntimeException e = new RuntimeException("here");
+            e.fillInStackTrace();
+            Log.w(TAG, "New hash " + hash
+                    + " is before end of array hash " + mHashes[index-1]
+                    + " at index " + index + " key " + key, e);
+            put(key, value);
+            return;
         }
         mSize = index+1;
         mHashes[index] = hash;
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index a4cc630..bb5a6eb 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -73,7 +73,7 @@
 
     SurfaceTexture getSurfaceTexture() {
         if (mSurface == null) {
-            mSurface = new SurfaceTexture(mTexture, false);
+            mSurface = new SurfaceTexture(mTexture);
         }
         return mSurface;
     }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0289407..aea2799c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -78,7 +78,7 @@
     void addWindowToken(IBinder token, int type);
     void removeWindowToken(IBinder token);
     void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId,
-            int requestedOrientation, boolean fullscreen, boolean showWhenLocked);
+            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId);
     void setAppGroupId(IBinder token, int groupId);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 2a761c1..debf4ee 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -44,6 +44,7 @@
 public final class InputDevice implements Parcelable {
     private final int mId;
     private final int mGeneration;
+    private final int mControllerNumber;
     private final String mName;
     private final String mDescriptor;
     private final boolean mIsExternal;
@@ -51,6 +52,7 @@
     private final int mKeyboardType;
     private final KeyCharacterMap mKeyCharacterMap;
     private final boolean mHasVibrator;
+    private final boolean mHasButtonUnderPad;
     private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
 
     private Vibrator mVibrator; // guarded by mMotionRanges during initialization
@@ -341,11 +343,12 @@
     };
 
     // Called by native code.
-    private InputDevice(int id, int generation, String name, String descriptor,
-            boolean isExternal, int sources,
-            int keyboardType, KeyCharacterMap keyCharacterMap, boolean hasVibrator) {
+    private InputDevice(int id, int generation, int controllerNumber, String name,
+            String descriptor, boolean isExternal, int sources, int keyboardType,
+            KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasButtonUnderPad) {
         mId = id;
         mGeneration = generation;
+        mControllerNumber = controllerNumber;
         mName = name;
         mDescriptor = descriptor;
         mIsExternal = isExternal;
@@ -353,11 +356,13 @@
         mKeyboardType = keyboardType;
         mKeyCharacterMap = keyCharacterMap;
         mHasVibrator = hasVibrator;
+        mHasButtonUnderPad = hasButtonUnderPad;
     }
 
     private InputDevice(Parcel in) {
         mId = in.readInt();
         mGeneration = in.readInt();
+        mControllerNumber = in.readInt();
         mName = in.readString();
         mDescriptor = in.readString();
         mIsExternal = in.readInt() != 0;
@@ -365,6 +370,7 @@
         mKeyboardType = in.readInt();
         mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
         mHasVibrator = in.readInt() != 0;
+        mHasButtonUnderPad = in.readInt() != 0;
 
         for (;;) {
             int axis = in.readInt();
@@ -410,6 +416,20 @@
     }
 
     /**
+     * The controller number for a given input device.
+     * <p>
+     * Each game controller or joystick is given a unique controller number when initially
+     * configured by the system. The number is not stable and may be changed by the system at any
+     * point.  All controller numbers will be non-negative. A game controller or joystick will be
+     * given a unique number indexed from one; everything else will be assigned a controller number
+     * of 0.
+     * </p>
+     */
+    public int getControllerNumber() {
+        return mControllerNumber;
+    }
+
+    /**
      * Gets a generation number for this input device.
      * The generation number is incremented whenever the device is reconfigured and its
      * properties may have changed.
@@ -612,6 +632,15 @@
     }
 
     /**
+     * Reports whether the device has a button under its touchpad
+     * @return Whether the device has a button under its touchpad
+     * @hide
+     */
+    public boolean hasButtonUnderPad() {
+        return mHasButtonUnderPad;
+    }
+
+    /**
      * Provides information about the range of values for a particular {@link MotionEvent} axis.
      *
      * @see InputDevice#getMotionRange(int)
@@ -726,6 +755,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mId);
         out.writeInt(mGeneration);
+        out.writeInt(mControllerNumber);
         out.writeString(mName);
         out.writeString(mDescriptor);
         out.writeInt(mIsExternal ? 1 : 0);
@@ -733,6 +763,7 @@
         out.writeInt(mKeyboardType);
         mKeyCharacterMap.writeToParcel(out, flags);
         out.writeInt(mHasVibrator ? 1 : 0);
+        out.writeInt(mHasButtonUnderPad ? 1 : 0);
 
         final int numRanges = mMotionRanges.size();
         for (int i = 0; i < numRanges; i++) {
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 73fad08..5a5fc10 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1837,6 +1837,19 @@
         }
     }
 
+    /** Whether key will, by default, trigger a click on the focused view.
+     * @hide
+     */
+    public static final boolean isConfirmKey(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_ENTER:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     /** {@inheritDoc} */
     @Override
     public final int getDeviceId() {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 95a2469..188ddf2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7945,21 +7945,17 @@
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         boolean result = false;
 
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_ENTER: {
-                if ((mViewFlags & ENABLED_MASK) == DISABLED) {
-                    return true;
-                }
-                // Long clickable items don't necessarily have to be clickable
-                if (((mViewFlags & CLICKABLE) == CLICKABLE ||
-                        (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) &&
-                        (event.getRepeatCount() == 0)) {
-                    setPressed(true);
-                    checkForLongClick(0);
-                    return true;
-                }
-                break;
+        if (KeyEvent.isConfirmKey(event.getKeyCode())) {
+            if ((mViewFlags & ENABLED_MASK) == DISABLED) {
+                return true;
+            }
+            // Long clickable items don't necessarily have to be clickable
+            if (((mViewFlags & CLICKABLE) == CLICKABLE ||
+                    (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) &&
+                    (event.getRepeatCount() == 0)) {
+                setPressed(true);
+                checkForLongClick(0);
+                return true;
             }
         }
         return result;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b0f67ac..075719c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -228,6 +228,7 @@
 
     InputStage mFirstInputStage;
     InputStage mFirstPostImeInputStage;
+    SyntheticInputStage mSyntheticInputStage;
 
     boolean mWindowAttributesChanged = false;
     int mWindowAttributesChangesFlag = 0;
@@ -589,8 +590,8 @@
 
                 // Set up the input pipeline.
                 CharSequence counterSuffix = attrs.getTitle();
-                InputStage syntheticStage = new SyntheticInputStage();
-                InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticStage);
+                mSyntheticInputStage = new SyntheticInputStage();
+                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                         "aq:native-post-ime:" + counterSuffix);
                 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
@@ -3773,6 +3774,9 @@
         private int processKeyEvent(QueuedInputEvent q) {
             final KeyEvent event = (KeyEvent)q.mEvent;
 
+            // The synthetic stage occasionally needs to know about keys in order to debounce taps
+            mSyntheticInputStage.notifyKeyEvent(event);
+
             // Deliver the key to the view hierarchy.
             if (mView.dispatchKeyEvent(event)) {
                 return FINISH_HANDLED;
@@ -3945,6 +3949,10 @@
             }
             super.onDeliverToNext(q);
         }
+
+        public void notifyKeyEvent(KeyEvent e) {
+            mTouchNavigation.notifyKeyEvent(e);
+        }
     }
 
     /**
@@ -4375,6 +4383,9 @@
         // Tap timeout in milliseconds.
         private static final int TAP_TIMEOUT = 250;
 
+        // Debounce timeout for touch nav devices with a button under their pad, in milliseconds
+        private static final int DEBOUNCE_TIME = 250;
+
         // The maximum distance traveled for a gesture to be considered a tap in millimeters.
         private static final int TAP_SLOP_MILLIMETERS = 5;
 
@@ -4409,6 +4420,9 @@
         private int mConfigTapTimeout;
         private float mConfigTapSlop;
 
+        // Amount of time to wait between button presses and tap generation for debouncing
+        private int mConfigDebounceTime;
+
         // The scaled tick distance.  A movement of this amount should generally translate
         // into a single dpad event in a given direction.
         private float mConfigTickDistance;
@@ -4454,6 +4468,11 @@
         private boolean mFlinging;
         private float mFlingVelocity;
 
+        // The last time a confirm key was pressed on the touch nav device
+        private long mLastConfirmKeyTime = Long.MAX_VALUE;
+
+        private boolean mHasButtonUnderPad;
+
         public SyntheticTouchNavigationHandler() {
             super(true);
         }
@@ -4497,6 +4516,8 @@
                                 MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
                         mConfigMaxFlingVelocity =
                                 MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
+                        mConfigDebounceTime = DEBOUNCE_TIME;
+                        mHasButtonUnderPad = device.hasButtonUnderPad();
 
                         if (LOCAL_DEBUG) {
                             Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
@@ -4567,10 +4588,13 @@
                         if (!mConsumedMovement
                                 && Math.hypot(mLastX - mStartX, mLastY - mStartY) < mConfigTapSlop
                                 && time <= mStartTime + mConfigTapTimeout) {
-                            // It's a tap!
-                            finishKeys(time);
-                            sendKeyDownOrRepeat(time, KeyEvent.KEYCODE_DPAD_CENTER, metaState);
-                            sendKeyUp(time);
+                            if (!mHasButtonUnderPad ||
+                                        time >= mLastConfirmKeyTime + mConfigDebounceTime) {
+                                // It's a tap!
+                                finishKeys(time);
+                                sendKeyDownOrRepeat(time, KeyEvent.KEYCODE_DPAD_CENTER, metaState);
+                                sendKeyUp(time);
+                            }
                         } else if (mConsumedMovement
                                 && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
                             // It might be a fling.
@@ -4603,6 +4627,13 @@
             }
         }
 
+        public void notifyKeyEvent(KeyEvent e) {
+            final int keyCode = e.getKeyCode();
+            if (KeyEvent.isConfirmKey(e.getKeyCode())) {
+                mLastConfirmKeyTime  = e.getDownTime();
+            }
+        }
+
         private void finishKeys(long time) {
             cancelFling();
             sendKeyUp(time);
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 9c00b7f..f0e6677 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -32,6 +32,7 @@
 import android.media.AudioSystem;
 import android.media.RingtoneManager;
 import android.media.ToneGenerator;
+import android.media.VolumeController;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
@@ -55,7 +56,8 @@
  *
  * @hide
  */
-public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener
+public class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener,
+        VolumeController
 {
     private static final String TAG = "VolumePanel";
     private static boolean LOGD = false;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 19e3905..f5c3b37 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2925,9 +2925,7 @@
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        switch (keyCode) {
-        case KeyEvent.KEYCODE_DPAD_CENTER:
-        case KeyEvent.KEYCODE_ENTER:
+        if (KeyEvent.isConfirmKey(keyCode)) {
             if (!isEnabled()) {
                 return true;
             }
@@ -2943,7 +2941,6 @@
                 setPressed(false);
                 return true;
             }
-            break;
         }
         return super.onKeyUp(keyCode, event);
     }
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index c4ef11c..78ba6e0 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1228,13 +1228,9 @@
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        switch (keyCode) {
-        case KeyEvent.KEYCODE_DPAD_CENTER:
-        case KeyEvent.KEYCODE_ENTER: {
-            
+        if (KeyEvent.isConfirmKey(keyCode)) {
             if (mReceivedInvokeKeyDown) {
                 if (mItemCount > 0) {
-    
                     dispatchPress(mSelectedChild);
                     postDelayed(new Runnable() {
                         @Override
@@ -1242,20 +1238,17 @@
                             dispatchUnpress();
                         }
                     }, ViewConfiguration.getPressedStateDuration());
-    
+
                     int selectedIndex = mSelectedPosition - mFirstPosition;
                     performItemClick(getChildAt(selectedIndex), mSelectedPosition, mAdapter
                             .getItemId(mSelectedPosition));
                 }
             }
-            
+
             // Clear the flag
             mReceivedInvokeKeyDown = false;
-            
             return true;
         }
-        }
-
         return super.onKeyUp(keyCode, event);
     }
     
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 3d6b69e..414c318 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -821,8 +821,7 @@
             // to select one of its items
             if (keyCode != KeyEvent.KEYCODE_SPACE
                     && (mDropDownList.getSelectedItemPosition() >= 0
-                            || (keyCode != KeyEvent.KEYCODE_ENTER
-                                    && keyCode != KeyEvent.KEYCODE_DPAD_CENTER))) {
+                            || !KeyEvent.isConfirmKey(keyCode))) {
                 int curIndex = mDropDownList.getSelectedItemPosition();
                 boolean consumed;
 
@@ -910,16 +909,10 @@
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
             boolean consumed = mDropDownList.onKeyUp(keyCode, event);
-            if (consumed) {
-                switch (keyCode) {
-                    // if the list accepts the key events and the key event
-                    // was a click, the text view gets the selected item
-                    // from the drop down as its content
-                    case KeyEvent.KEYCODE_ENTER:
-                    case KeyEvent.KEYCODE_DPAD_CENTER:
-                        dismiss();
-                        break;
-                }
+            if (consumed && KeyEvent.isConfirmKey(keyCode)) {
+                // if the list accepts the key events and the key event was a click, the text view
+                // gets the selected item from the drop down as its content
+                dismiss();
             }
             return consumed;
         }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 07e66b7..0d3df51 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -37,6 +37,7 @@
 import android.os.StrictMode;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.LayoutInflater.Filter;
@@ -45,6 +46,7 @@
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.AdapterView.OnItemClickListener;
+import libcore.util.Objects;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -136,6 +138,49 @@
 
     private static final OnClickHandler DEFAULT_ON_CLICK_HANDLER = new OnClickHandler();
 
+    private static final Object[] sMethodsLock = new Object[0];
+    private static final ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>> sMethods =
+            new ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>>();
+    private static final ThreadLocal<Object[]> sInvokeArgsTls = new ThreadLocal<Object[]>() {
+        @Override
+        protected Object[] initialValue() {
+            return new Object[1];
+        }
+    };
+
+    /**
+     * Handle with care!
+     */
+    static class MutablePair<F, S> {
+        F first;
+        S second;
+
+        MutablePair(F first, S second) {
+            this.first = first;
+            this.second = second;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof MutablePair)) {
+                return false;
+            }
+            MutablePair<?, ?> p = (MutablePair<?, ?>) o;
+            return Objects.equal(p.first, first) && Objects.equal(p.second, second);
+        }
+
+        @Override
+        public int hashCode() {
+            return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
+        }
+    }
+
+    /**
+     * This pair is used to perform lookups in sMethods without causing allocations.
+     */
+    private final MutablePair<String, Class<?>> mPair =
+            new MutablePair<String, Class<?>>(null, null);
+
     /**
      * This annotation indicates that a subclass of View is alllowed to be used
      * with the {@link RemoteViews} mechanism.
@@ -206,9 +251,8 @@
          * Overridden by each class to report on it's own memory usage
          */
         public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
-            // We currently only calculate Bitmap memory usage, so by default, don't do anything
-            // here
-            return;
+            // We currently only calculate Bitmap memory usage, so by default,
+            // don't do anything here
         }
 
         public void setBitmapCache(BitmapCache bitmapCache) {
@@ -346,7 +390,7 @@
             }
             if (target == root) {
                 target.setTagInternal(com.android.internal.R.id.fillInIntent, fillInIntent);
-            } else if (target != null && fillInIntent != null) {
+            } else if (fillInIntent != null) {
                 OnClickListener listener = new OnClickListener() {
                     public void onClick(View v) {
                         // Insure that this view is a child of an AdapterView
@@ -372,16 +416,7 @@
 
                         PendingIntent pendingIntent = (PendingIntent) parent.getTag();
 
-                        final float appScale = v.getContext().getResources()
-                                .getCompatibilityInfo().applicationScale;
-                        final int[] pos = new int[2];
-                        v.getLocationOnScreen(pos);
-
-                        final Rect rect = new Rect();
-                        rect.left = (int) (pos[0] * appScale + 0.5f);
-                        rect.top = (int) (pos[1] * appScale + 0.5f);
-                        rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
-                        rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
+                        final Rect rect = getSourceBounds(v);
 
                         fillInIntent.setSourceBounds(rect);
                         handler.onClickHandler(v, pendingIntent, fillInIntent);
@@ -452,16 +487,7 @@
                             }
                             if (fillInIntent == null) return;
 
-                            final float appScale = view.getContext().getResources()
-                                    .getCompatibilityInfo().applicationScale;
-                            final int[] pos = new int[2];
-                            view.getLocationOnScreen(pos);
-
-                            final Rect rect = new Rect();
-                            rect.left = (int) (pos[0] * appScale + 0.5f);
-                            rect.top = (int) (pos[1] * appScale + 0.5f);
-                            rect.right = (int) ((pos[0] + view.getWidth()) * appScale + 0.5f);
-                            rect.bottom = (int) ((pos[1] + view.getHeight()) * appScale + 0.5f);
+                            final Rect rect = getSourceBounds(view);
 
                             final Intent intent = new Intent();
                             intent.setSourceBounds(rect);
@@ -679,33 +705,22 @@
                 }
             }
 
-            if (target != null) {
-                // If the pendingIntent is null, we clear the onClickListener
-                OnClickListener listener = null;
-                if (pendingIntent != null) {
-                    listener = new OnClickListener() {
-                        public void onClick(View v) {
-                            // Find target view location in screen coordinates and
-                            // fill into PendingIntent before sending.
-                            final float appScale = v.getContext().getResources()
-                                    .getCompatibilityInfo().applicationScale;
-                            final int[] pos = new int[2];
-                            v.getLocationOnScreen(pos);
+            // If the pendingIntent is null, we clear the onClickListener
+            OnClickListener listener = null;
+            if (pendingIntent != null) {
+                listener = new OnClickListener() {
+                    public void onClick(View v) {
+                        // Find target view location in screen coordinates and
+                        // fill into PendingIntent before sending.
+                        final Rect rect = getSourceBounds(v);
 
-                            final Rect rect = new Rect();
-                            rect.left = (int) (pos[0] * appScale + 0.5f);
-                            rect.top = (int) (pos[1] * appScale + 0.5f);
-                            rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
-                            rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
-
-                            final Intent intent = new Intent();
-                            intent.setSourceBounds(rect);
-                            handler.onClickHandler(v, pendingIntent, intent);
-                        }
-                    };
-                }
-                target.setOnClickListener(listener);
+                        final Intent intent = new Intent();
+                        intent.setSourceBounds(rect);
+                        handler.onClickHandler(v, pendingIntent, intent);
+                    }
+                };
             }
+            target.setOnClickListener(listener);
         }
 
         public String getActionName() {
@@ -717,6 +732,71 @@
         public final static int TAG = 1;
     }
 
+    private static Rect getSourceBounds(View v) {
+        final float appScale = v.getContext().getResources()
+                .getCompatibilityInfo().applicationScale;
+        final int[] pos = new int[2];
+        v.getLocationOnScreen(pos);
+
+        final Rect rect = new Rect();
+        rect.left = (int) (pos[0] * appScale + 0.5f);
+        rect.top = (int) (pos[1] * appScale + 0.5f);
+        rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
+        rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
+        return rect;
+    }
+
+    private Method getMethod(View view, String methodName, Class<?> paramType) {
+        Method method;
+        Class<? extends View> klass = view.getClass();
+
+        synchronized (sMethodsLock) {
+            ArrayMap<MutablePair<String, Class<?>>, Method> methods = sMethods.get(klass);
+            if (methods == null) {
+                methods = new ArrayMap<MutablePair<String, Class<?>>, Method>();
+                sMethods.put(klass, methods);
+            }
+
+            mPair.first = methodName;
+            mPair.second = paramType;
+
+            method = methods.get(mPair);
+            if (method == null) {
+                try {
+                    if (paramType == null) {
+                        method = klass.getMethod(methodName);
+                    } else {
+                        method = klass.getMethod(methodName, paramType);
+                    }
+                } catch (NoSuchMethodException ex) {
+                    throw new ActionException("view: " + klass.getName() + " doesn't have method: "
+                            + methodName + getParameters(paramType));
+                }
+
+                if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
+                    throw new ActionException("view: " + klass.getName()
+                            + " can't use method with RemoteViews: "
+                            + methodName + getParameters(paramType));
+                }
+
+                methods.put(new MutablePair<String, Class<?>>(methodName, paramType), method);
+            }
+        }
+
+        return method;
+    }
+
+    private static String getParameters(Class<?> paramType) {
+        if (paramType == null) return "()";
+        return "(" + paramType + ")";
+    }
+
+    private static Object[] wrapArg(Object value) {
+        Object[] args = sInvokeArgsTls.get();
+        args[0] = value;
+        return args;
+    }
+
     /**
      * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
      * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
@@ -810,8 +890,8 @@
         public final static int TAG = 3;
     }
 
-    private class ReflectionActionWithoutParams extends Action {
-        String methodName;
+    private final class ReflectionActionWithoutParams extends Action {
+        final String methodName;
 
         public final static int TAG = 5;
 
@@ -836,28 +916,10 @@
             final View view = root.findViewById(viewId);
             if (view == null) return;
 
-            Class klass = view.getClass();
-            Method method;
             try {
-                method = klass.getMethod(this.methodName);
-            } catch (NoSuchMethodException ex) {
-                throw new ActionException("view: " + klass.getName() + " doesn't have method: "
-                        + this.methodName + "()");
-            }
-
-            if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
-                throw new ActionException("view: " + klass.getName()
-                        + " can't use method with RemoteViews: "
-                        + this.methodName + "()");
-            }
-
-            try {
-                //noinspection ConstantIfStatement
-                if (false) {
-                    Log.d(LOG_TAG, "view: " + klass.getName() + " calling method: "
-                        + this.methodName + "()");
-                }
-                method.invoke(view);
+                getMethod(view, this.methodName, null).invoke(view);
+            } catch (ActionException e) {
+                throw e;
             } catch (Exception ex) {
                 throw new ActionException(ex);
             }
@@ -990,7 +1052,7 @@
     /**
      * Base class for the reflection actions.
      */
-    private class ReflectionAction extends Action {
+    private final class ReflectionAction extends Action {
         static final int TAG = 2;
 
         static final int BOOLEAN = 1;
@@ -1157,7 +1219,7 @@
             }
         }
 
-        private Class getParameterType() {
+        private Class<?> getParameterType() {
             switch (this.type) {
                 case BOOLEAN:
                     return boolean.class;
@@ -1197,37 +1259,16 @@
             final View view = root.findViewById(viewId);
             if (view == null) return;
 
-            Class param = getParameterType();
+            Class<?> param = getParameterType();
             if (param == null) {
                 throw new ActionException("bad type: " + this.type);
             }
 
-            Class klass = view.getClass();
-            Method method;
             try {
-                method = klass.getMethod(this.methodName, getParameterType());
-            }
-            catch (NoSuchMethodException ex) {
-                throw new ActionException("view: " + klass.getName() + " doesn't have method: "
-                        + this.methodName + "(" + param.getName() + ")");
-            }
-
-            if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
-                throw new ActionException("view: " + klass.getName()
-                        + " can't use method with RemoteViews: "
-                        + this.methodName + "(" + param.getName() + ")");
-            }
-
-            try {
-                //noinspection ConstantIfStatement
-                if (false) {
-                    Log.d(LOG_TAG, "view: " + klass.getName() + " calling method: "
-                        + this.methodName + "(" + param.getName() + ") with "
-                        + (this.value == null ? "null" : this.value.getClass().getName()));
-                }
-                method.invoke(view, this.value);
-            }
-            catch (Exception ex) {
+                getMethod(view, this.methodName, param).invoke(view, wrapArg(this.value));
+            } catch (ActionException e) {
+                throw e;
+            } catch (Exception ex) {
                 throw new ActionException(ex);
             }
         }
@@ -1323,7 +1364,7 @@
         }
 
         public String getActionName() {
-            return "ViewGroupAction" + this.nestedViews == null ? "Remove" : "Add";
+            return "ViewGroupAction" + (nestedViews == null ? "Remove" : "Add");
         }
 
         public int mergeBehavior() {
@@ -1370,7 +1411,6 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final Context context = root.getContext();
             final TextView target = (TextView) root.findViewById(viewId);
             if (target == null) return;
             if (isRelative) {
@@ -1415,7 +1455,6 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final Context context = root.getContext();
             final TextView target = (TextView) root.findViewById(viewId);
             if (target == null) return;
             target.setTextSize(units, size);
@@ -1462,7 +1501,6 @@
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
-            final Context context = root.getContext();
             final View target = root.findViewById(viewId);
             if (target == null) return;
             target.setPadding(left, top, right, bottom);
@@ -1494,6 +1532,7 @@
             return mMemoryUsage;
         }
 
+        @SuppressWarnings("deprecation")
         public void addBitmapMemory(Bitmap b) {
             final Bitmap.Config c = b.getConfig();
             // If we don't know, be pessimistic and assume 4
@@ -1597,7 +1636,7 @@
         if (mode == MODE_NORMAL) {
             mPackage = parcel.readString();
             mLayoutId = parcel.readInt();
-            mIsWidgetCollectionChild = parcel.readInt() == 1 ? true : false;
+            mIsWidgetCollectionChild = parcel.readInt() == 1;
 
             int count = parcel.readInt();
             if (count > 0) {
diff --git a/core/java/com/android/internal/app/RestrictionsPinActivity.java b/core/java/com/android/internal/app/RestrictionsPinActivity.java
index 57436f7..f8ce108 100644
--- a/core/java/com/android/internal/app/RestrictionsPinActivity.java
+++ b/core/java/com/android/internal/app/RestrictionsPinActivity.java
@@ -26,6 +26,7 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.WindowManager;
 import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
@@ -39,17 +40,24 @@
 public class RestrictionsPinActivity extends AlertActivity
         implements DialogInterface.OnClickListener, TextWatcher, OnEditorActionListener {
 
-    private UserManager mUserManager;
+    protected UserManager mUserManager;
+    protected boolean mHasRestrictionsPin;
 
-    private EditText mPin1Text;
-    private EditText mPin2Text;
-    private TextView mPinErrorMessage;
-    private TextView mPinMessage;
+    protected EditText mPinText;
+    protected TextView mPinErrorMessage;
+    protected TextView mPinMessage;
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
+        mHasRestrictionsPin = mUserManager.hasRestrictionsPin();
+        initUi();
+        setupAlert();
+    }
+
+    protected void initUi() {
         AlertController.AlertParams ap = mAlertParams;
         ap.mTitle = getString(R.string.restr_pin_enter_pin);
         ap.mPositiveButtonText = getString(R.string.ok);
@@ -58,18 +66,12 @@
         ap.mNegativeButtonListener = this;
         LayoutInflater inflater =
                 (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        ap.mView = inflater.inflate(R.layout.pin_challenge, null);
+        ap.mView = inflater.inflate(R.layout.restrictions_pin_challenge, null);
 
         mPinMessage = (TextView) ap.mView.findViewById(R.id.pin_message);
-        mPin1Text = (EditText) ap.mView.findViewById(R.id.pin1_text);
-        mPin2Text = (EditText) ap.mView.findViewById(R.id.pin2_text);
+        mPinText = (EditText) ap.mView.findViewById(R.id.pin_text);
         mPinErrorMessage = (TextView) ap.mView.findViewById(R.id.pin_error_message);
-        mPin1Text.addTextChangedListener(this);
-        mPin2Text.addTextChangedListener(this);
-
-        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
-
-        setupAlert();
+        mPinText.addTextChangedListener(this);
     }
 
     protected boolean verifyingPin() {
@@ -81,19 +83,12 @@
 
         setPositiveButtonState(false);
         boolean hasPin = mUserManager.hasRestrictionsPin();
-        if (verifyingPin()) {
-            if (hasPin) {
-                mPinMessage.setVisibility(View.GONE);
-                mPinErrorMessage.setVisibility(View.GONE);
-                mPin2Text.setVisibility(View.GONE);
-                mPin1Text.setOnEditorActionListener(this);
-                updatePinTimer(-1);
-            } else {
-                setResult(RESULT_OK);
-                finish();
-            }
-        } else if (hasPin) {
-            // Shouldn't really be in this state, exit
+        if (hasPin) {
+            mPinMessage.setVisibility(View.GONE);
+            mPinErrorMessage.setVisibility(View.GONE);
+            mPinText.setOnEditorActionListener(this);
+            updatePinTimer(-1);
+        } else if (verifyingPin()) {
             setResult(RESULT_OK);
             finish();
         }
@@ -114,14 +109,14 @@
                     seconds);
             mPinErrorMessage.setText(String.format(formatString, seconds));
             mPinErrorMessage.setVisibility(View.VISIBLE);
-            mPin1Text.setEnabled(false);
-            mPin1Text.setText("");
+            mPinText.setEnabled(false);
+            mPinText.setText("");
             setPositiveButtonState(false);
-            mPin1Text.postDelayed(mCountdownRunnable, Math.min(1000, pinTimerMs));
+            mPinText.postDelayed(mCountdownRunnable, Math.min(1000, pinTimerMs));
         } else {
             mPinErrorMessage.setVisibility(View.INVISIBLE);
-            mPin1Text.setEnabled(true);
-            mPin1Text.setText("");
+            mPinText.setEnabled(true);
+            mPinText.setText("");
         }
     }
 
@@ -134,20 +129,13 @@
         }
     }
 
-    private void performPositiveButtonAction() {
-        if (verifyingPin()) {
-            int result = mUserManager.checkRestrictionsPin(mPin1Text.getText().toString());
-            if (result == UserManager.PIN_VERIFICATION_SUCCESS) {
-                setResult(RESULT_OK);
-                finish();
-            } else if (result >= 0) {
-                updatePinTimer(result);
-            }
-        } else {
-            if (mUserManager.changeRestrictionsPin(mPin1Text.getText().toString())) {
-                setResult(RESULT_OK);
-                finish();
-            }
+    protected void performPositiveButtonAction() {
+        int result = mUserManager.checkRestrictionsPin(mPinText.getText().toString());
+        if (result == UserManager.PIN_VERIFICATION_SUCCESS) {
+            setResult(RESULT_OK);
+            finish();
+        } else if (result >= 0) {
+            updatePinTimer(result);
         }
     }
 
@@ -157,16 +145,8 @@
 
     @Override
     public void onTextChanged(CharSequence s, int start, int before, int count) {
-        CharSequence pin1 = mPin1Text.getText();
-        if (!verifyingPin()) {
-            CharSequence pin2 = mPin2Text.getText();
-            boolean match = pin1 != null && pin2 != null && pin1.length() >= 4
-                    && pin1.toString().equals(pin2.toString());
-            setPositiveButtonState(match);
-            mPinErrorMessage.setVisibility(match ? View.INVISIBLE : View.VISIBLE);
-        } else {
-            setPositiveButtonState(pin1 != null && pin1.length() >= 4);
-        }
+        CharSequence pin = mPinText.getText();
+        setPositiveButtonState(pin != null && pin.length() >= 4);
     }
 
     @Override
diff --git a/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java b/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java
index 35f2967..1d09292 100644
--- a/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java
+++ b/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java
@@ -16,13 +16,115 @@
 
 package com.android.internal.app;
 
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.UserManager;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
 /**
  * This activity is launched by Settings and other apps to either create a new PIN or
- * challenge for an existing PIN. The PIN is maintained by UserManager.
+ * change an existing PIN. The PIN is maintained by UserManager.
  */
 public class RestrictionsPinSetupActivity extends RestrictionsPinActivity {
 
+    private EditText mNewPinText;
+    private EditText mConfirmPinText;
+
+    protected void initUi() {
+        AlertController.AlertParams ap = mAlertParams;
+        ap.mTitle = getString(R.string.restr_pin_enter_pin);
+        ap.mPositiveButtonText = getString(R.string.ok);
+        ap.mNegativeButtonText = getString(R.string.cancel);
+        ap.mPositiveButtonListener = this;
+        ap.mNegativeButtonListener = this;
+        LayoutInflater inflater =
+                (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        ap.mView = inflater.inflate(R.layout.restrictions_pin_setup, null);
+
+        mPinText = (EditText) ap.mView.findViewById(R.id.pin_text);
+        mPinMessage = (TextView) ap.mView.findViewById(R.id.pin_message);
+        mNewPinText = (EditText) ap.mView.findViewById(R.id.pin_new_text);
+        mConfirmPinText = (EditText) ap.mView.findViewById(R.id.pin_confirm_text);
+        mPinErrorMessage = (TextView) ap.mView.findViewById(R.id.pin_error_message);
+        mNewPinText.addTextChangedListener(this);
+        mConfirmPinText.addTextChangedListener(this);
+
+        if (!mHasRestrictionsPin) {
+            mPinText.setVisibility(View.GONE);
+        }
+    }
+
+    public void onResume() {
+        super.onResume();
+        setPositiveButtonState(false);
+    }
+
     protected boolean verifyingPin() {
         return false;
     }
+
+    private void setPositiveButtonState(boolean enabled) {
+        mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(enabled);
+    }
+
+    public void onClick(DialogInterface dialog, int which) {
+        setResult(RESULT_CANCELED);
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            performPositiveButtonAction();
+        } else if (which == AlertDialog.BUTTON_NEGATIVE) {
+            finish();
+        }
+    }
+
+    protected void performPositiveButtonAction() {
+        if (mHasRestrictionsPin) {
+            int result = mUserManager.checkRestrictionsPin(mPinText.getText().toString());
+            if (result != UserManager.PIN_VERIFICATION_SUCCESS) {
+                // TODO: Set message that existing pin doesn't match
+                return;
+            }
+        }
+        if (mUserManager.changeRestrictionsPin(mNewPinText.getText().toString())) {
+            // TODO: Send message to PIN recovery agent about the recovery email address
+            setResult(RESULT_OK);
+            finish();
+        }
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+        CharSequence pin = mPinText.getText();
+        CharSequence pin1 = mNewPinText.getText();
+        CharSequence pin2 = mConfirmPinText.getText();
+        boolean match = pin1 != null && pin2 != null && pin1.length() >= 4
+                && pin1.toString().equals(pin2.toString())
+                && (!mHasRestrictionsPin || (pin != null && pin.length() >= 4));
+        boolean showError = !TextUtils.isEmpty(pin1) && !TextUtils.isEmpty(pin2);
+        // TODO: Check recovery email address as well
+        setPositiveButtonState(match);
+        mPinErrorMessage.setVisibility((match || !showError) ? View.INVISIBLE : View.VISIBLE);
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+    }
+
+    @Override
+    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+        performPositiveButtonAction();
+        return true;
+    }
 }
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index abf99a3..98599d0 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.net.RouteInfo;
 import android.net.LinkAddress;
 
@@ -50,15 +51,12 @@
         return intent;
     }
 
-    public static PendingIntent getIntentForStatusPanel(Context context, VpnConfig config) {
-        Preconditions.checkNotNull(config);
-
+    public static PendingIntent getIntentForStatusPanel(Context context) {
         Intent intent = new Intent();
         intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
-        intent.putExtra("config", config);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
                 Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+        return PendingIntent.getActivityAsUser(context, 0, intent, 0, null, UserHandle.CURRENT);
     }
 
     public String user;
diff --git a/core/java/com/android/internal/notification/DemoContactNotificationScorer.java b/core/java/com/android/internal/notification/DemoContactNotificationScorer.java
new file mode 100644
index 0000000..081a371
--- /dev/null
+++ b/core/java/com/android/internal/notification/DemoContactNotificationScorer.java
@@ -0,0 +1,188 @@
+/*
+* Copyright (C) 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.internal.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.Settings;
+import android.text.SpannableString;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This NotificationScorer bumps up the priority of notifications that contain references to the
+ * display names of starred contacts. The references it picks up are spannable strings which, in
+ * their entirety, match the display name of some starred contact. The magnitude of the bump ranges
+ * from 0 to 15 (assuming NOTIFICATION_PRIORITY_MULTIPLIER = 10) depending on the initial score, and
+ * the mapping is defined by priorityBumpMap. In a production version of this scorer, a notification
+ * extra will be used to specify contact identifiers.
+ */
+
+public class DemoContactNotificationScorer implements NotificationScorer {
+    private static final String TAG = "StarredContactScoring";
+    private static final boolean DBG = true;
+
+    protected static final boolean ENABLE_CONTACT_SCORER = true;
+    private static final String SETTING_ENABLE_SCORER = "contact_scorer_enabled";
+    protected boolean mEnabled;
+
+    // see NotificationManagerService
+    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
+
+    private Context mContext;
+
+    private static final List<String> RELEVANT_KEYS_LIST = Arrays.asList(
+            Notification.EXTRA_INFO_TEXT, Notification.EXTRA_TEXT, Notification.EXTRA_TEXT_LINES,
+            Notification.EXTRA_SUB_TEXT, Notification.EXTRA_TITLE
+    );
+
+    private static final String[] PROJECTION = new String[] {
+            ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME
+    };
+
+    private static final Uri CONTACTS_URI = ContactsContract.Contacts.CONTENT_URI;
+
+    private static List<String> extractSpannedStrings(CharSequence charSequence) {
+        if (charSequence == null) return Collections.emptyList();
+        if (!(charSequence instanceof SpannableString)) {
+            return Arrays.asList(charSequence.toString());
+        }
+        SpannableString spannableString = (SpannableString)charSequence;
+        // get all spans
+        Object[] ssArr = spannableString.getSpans(0, spannableString.length(), Object.class);
+        // spanned string sequences
+        ArrayList<String> sss = new ArrayList<String>();
+        for (Object spanObj : ssArr) {
+            try {
+                sss.add(spannableString.subSequence(spannableString.getSpanStart(spanObj),
+                        spannableString.getSpanEnd(spanObj)).toString());
+            } catch(StringIndexOutOfBoundsException e) {
+                Slog.e(TAG, "Bad indices when extracting spanned subsequence", e);
+            }
+        }
+        return sss;
+    };
+
+    private static String getQuestionMarksInParens(int n) {
+        StringBuilder sb = new StringBuilder("(");
+        for (int i = 0; i < n; i++) {
+            if (sb.length() > 1) sb.append(',');
+            sb.append('?');
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    private boolean hasStarredContact(Bundle extras) {
+        if (extras == null) return false;
+        ArrayList<String> qStrings = new ArrayList<String>();
+        // build list to query against the database for display names.
+        for (String rk: RELEVANT_KEYS_LIST) {
+            if (extras.get(rk) == null) {
+                continue;
+            } else if (extras.get(rk) instanceof CharSequence) {
+                qStrings.addAll(extractSpannedStrings((CharSequence) extras.get(rk)));
+            } else if (extras.get(rk) instanceof CharSequence[]) {
+                // this is intended for Notification.EXTRA_TEXT_LINES
+                for (CharSequence line: (CharSequence[]) extras.get(rk)){
+                    qStrings.addAll(extractSpannedStrings(line));
+                }
+            } else {
+                Slog.w(TAG, "Strange, the extra " + rk + " is of unexpected type.");
+            }
+        }
+        if (qStrings.isEmpty()) return false;
+        String[] qStringsArr = qStrings.toArray(new String[qStrings.size()]);
+
+        String selection = ContactsContract.Contacts.DISPLAY_NAME + " IN "
+                + getQuestionMarksInParens(qStringsArr.length) + " AND "
+                + ContactsContract.Contacts.STARRED+" ='1'";
+
+        Cursor c = null;
+        try {
+            c = mContext.getContentResolver().query(
+                    CONTACTS_URI, PROJECTION, selection, qStringsArr, null);
+            if (c != null) return c.getCount() > 0;
+        } catch(Throwable t) {
+            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        return false;
+    }
+
+    private final static int clamp(int x, int low, int high) {
+        return (x < low) ? low : ((x > high) ? high : x);
+    }
+
+    private static int priorityBumpMap(int incomingScore) {
+        //assumption is that scale runs from [-2*pm, 2*pm]
+        int pm = NOTIFICATION_PRIORITY_MULTIPLIER;
+        int theScore = incomingScore;
+        // enforce input in range
+        theScore = clamp(theScore, -2 * pm, 2 * pm);
+        if (theScore != incomingScore) return incomingScore;
+        // map -20 -> -20 and -10 -> 5 (when pm = 10)
+        if (theScore <= -pm) {
+            theScore += 1.5 * (theScore + 2 * pm);
+        } else {
+            // map 0 -> 10, 10 -> 15, 20 -> 20;
+            theScore += 0.5 * (2 * pm - theScore);
+        }
+        if (DBG) Slog.v(TAG, "priorityBumpMap: score before: " + incomingScore
+                + ", score after " + theScore + ".");
+        return theScore;
+    }
+
+    @Override
+    public void initialize(Context context) {
+        if (DBG) Slog.v(TAG, "Initializing  " + getClass().getSimpleName() + ".");
+        mContext = context;
+        mEnabled = ENABLE_CONTACT_SCORER && 1 == Settings.Global.getInt(
+                mContext.getContentResolver(), SETTING_ENABLE_SCORER, 1);
+    }
+
+    @Override
+    public int getScore(Notification notification, int score) {
+        if (notification == null || !mEnabled) {
+            if (DBG) Slog.w(TAG, "empty notification? scorer disabled?");
+            return score;
+        }
+        boolean hasStarredPriority = hasStarredContact(notification.extras);
+
+        if (DBG) {
+            if (hasStarredPriority) {
+                Slog.v(TAG, "Notification references starred contact. Promoted!");
+            } else {
+                Slog.v(TAG, "Notification lacks any starred contact reference. Not promoted!");
+            }
+        }
+        if (hasStarredPriority) score = priorityBumpMap(score);
+        return score;
+    }
+}
+
diff --git a/core/java/com/android/internal/notification/NotificationScorer.java b/core/java/com/android/internal/notification/NotificationScorer.java
new file mode 100644
index 0000000..863c08c
--- /dev/null
+++ b/core/java/com/android/internal/notification/NotificationScorer.java
@@ -0,0 +1,27 @@
+/*
+* Copyright (C) 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.internal.notification;
+
+import android.app.Notification;
+import android.content.Context;
+
+public interface NotificationScorer {
+
+    public void initialize(Context context);
+    public int getScore(Notification notification, int score);
+
+}
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 3600b76..bf9177b 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -197,11 +197,10 @@
     }
 }
 
-static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
-        jobject weakThiz, jboolean allowSynchronous)
+static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName, jobject weakThiz)
 {
-    sp<BufferQueue> bq = new BufferQueue(allowSynchronous);
-    sp<GLConsumer> surfaceTexture(new GLConsumer(bq, texName));
+    sp<BufferQueue> bq = new BufferQueue();
+    sp<GLConsumer> surfaceTexture(new GLConsumer(bq, texName, GL_TEXTURE_EXTERNAL_OES, true, true));
     if (surfaceTexture == 0) {
         jniThrowException(env, OutOfResourcesException,
                 "Unable to create native SurfaceTexture");
@@ -286,7 +285,7 @@
 
 static JNINativeMethod gSurfaceTextureMethods[] = {
     {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
-    {"nativeInit",                 "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init },
+    {"nativeInit",                 "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init },
     {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
     {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
     {"nativeUpdateTexImage",       "()V",   (void*)SurfaceTexture_updateTexImage },
diff --git a/core/jni/android_hardware_photography_CameraMetadata.cpp b/core/jni/android_hardware_photography_CameraMetadata.cpp
index 5070d2c..5190a37 100644
--- a/core/jni/android_hardware_photography_CameraMetadata.cpp
+++ b/core/jni/android_hardware_photography_CameraMetadata.cpp
@@ -267,7 +267,13 @@
 
     if (src == NULL) {
         // If array is NULL, delete the entry
-        res = metadata->erase(tag);
+        if (metadata->exists(tag)) {
+            res = metadata->erase(tag);
+            ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
+        } else {
+            res = OK;
+            ALOGV("%s: Don't need to erase", __FUNCTION__);
+        }
     } else {
         // Copy from java array into native array
         ScopedByteArrayRO arrayReader(env, src);
@@ -275,6 +281,8 @@
 
         res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
                                  tagType, arrayReader.get(), arrayReader.size());
+
+        ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
     }
 
     if (res == OK) {
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 197d240..77208b9 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -18,22 +18,12 @@
 
 #define LOG_TAG "AudioRecord-JNI"
 
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <math.h>
-
 #include <jni.h>
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
 #include <utils/Log.h>
-#include <utils/SortedVector.h>
-#include <utils/threads.h>
 #include <media/AudioRecord.h>
-#include <media/mediarecorder.h>
-
-#include <cutils/bitops.h>
 
 #include <system/audio.h>
 
@@ -101,12 +91,9 @@
         }
         callbackInfo->busy = true;
     }
-    if (event == AudioRecord::EVENT_MORE_DATA) {
-        // set size to 0 to signal we're not using the callback to read more data
-        AudioRecord::Buffer* pBuff = (AudioRecord::Buffer*)info;
-        pBuff->size = 0;
 
-    } else if (event == AudioRecord::EVENT_MARKER) {
+    switch (event) {
+    case AudioRecord::EVENT_MARKER: {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
         if (user && env) {
             env->CallStaticVoidMethod(
@@ -118,8 +105,9 @@
                 env->ExceptionClear();
             }
         }
+        } break;
 
-    } else if (event == AudioRecord::EVENT_NEW_POS) {
+    case AudioRecord::EVENT_NEW_POS: {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
         if (user && env) {
             env->CallStaticVoidMethod(
@@ -131,7 +119,9 @@
                 env->ExceptionClear();
             }
         }
+        } break;
     }
+
     {
         Mutex::Autolock l(sLock);
         callbackInfo->busy = false;
@@ -402,10 +392,13 @@
                                                         jshortArray javaAudioData,
                                                         jint offsetInShorts, jint sizeInShorts) {
 
-    return (android_media_AudioRecord_readInByteArray(env, thiz,
+    jint read = android_media_AudioRecord_readInByteArray(env, thiz,
                                                         (jbyteArray) javaAudioData,
-                                                        offsetInShorts*2, sizeInShorts*2)
-            / 2);
+                                                        offsetInShorts*2, sizeInShorts*2);
+    if (read > 0) {
+        read /= 2;
+    }
+    return read;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 45561d3..d6c5e4f 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -18,11 +18,6 @@
 #define LOG_TAG "AudioSystem"
 #include <utils/Log.h>
 
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <math.h>
-
 #include <jni.h>
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
@@ -312,6 +307,12 @@
     return (jint) afLatency;
 }
 
+static jint
+android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
+{
+    return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
@@ -338,6 +339,7 @@
     {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
     {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
     {"getOutputLatency",    "(I)I",     (void *)android_media_AudioSystem_getOutputLatency},
+    {"setLowRamDevice",     "(Z)I",     (void *)android_media_AudioSystem_setLowRamDevice},
 };
 
 int register_android_media_AudioSystem(JNIEnv *env)
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 942d33f..a9a87d6 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -17,11 +17,6 @@
 
 #define LOG_TAG "AudioTrack-JNI"
 
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <math.h>
-
 #include <jni.h>
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
@@ -33,8 +28,6 @@
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
 
-#include <cutils/bitops.h>
-
 #include <system/audio.h>
 
 // ----------------------------------------------------------------------------
@@ -47,8 +40,6 @@
 struct fields_t {
     // these fields provide access from C++ to the...
     jmethodID postNativeEventInJava; //... event post callback method
-    int       PCM16;                 //...  format constants
-    int       PCM8;                  //...  format constants
     jfieldID  nativeTrackInJavaObj;  // stores in Java the native AudioTrack object
     jfieldID  jniData;      // stores in Java additional resources used by the native AudioTrack
 };
@@ -64,6 +55,9 @@
 // keep these values in sync with AudioTrack.java
 #define MODE_STATIC 0
 #define MODE_STREAM 1
+// keep these values in sync with AudioFormat.java
+#define ENCODING_PCM_16BIT 2
+#define ENCODING_PCM_8BIT  3
 
 // ----------------------------------------------------------------------------
 class AudioTrackJniStorage {
@@ -137,12 +131,8 @@
         callbackInfo->busy = true;
     }
 
-    if (event == AudioTrack::EVENT_MORE_DATA) {
-        // set size to 0 to signal we're not using the callback to write more data
-        AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info;
-        pBuff->size = 0;
-
-    } else if (event == AudioTrack::EVENT_MARKER) {
+    switch (event) {
+    case AudioTrack::EVENT_MARKER: {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
         if (user && env) {
             env->CallStaticVoidMethod(
@@ -154,8 +144,9 @@
                 env->ExceptionClear();
             }
         }
+        } break;
 
-    } else if (event == AudioTrack::EVENT_NEW_POS) {
+    case AudioTrack::EVENT_NEW_POS: {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
         if (user && env) {
             env->CallStaticVoidMethod(
@@ -167,7 +158,9 @@
                 env->ExceptionClear();
             }
         }
+        } break;
     }
+
     {
         Mutex::Autolock l(sLock);
         callbackInfo->busy = false;
@@ -251,7 +244,8 @@
 
     // check the format.
     // This function was called from Java, so we compare the format against the Java constants
-    if ((audioFormat != javaAudioTrackFields.PCM16) && (audioFormat != javaAudioTrackFields.PCM8)) {
+    if ((audioFormat != ENCODING_PCM_16BIT) && (audioFormat != ENCODING_PCM_8BIT)) {
+
         ALOGE("Error creating AudioTrack: unsupported audio format.");
         return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
     }
@@ -259,19 +253,19 @@
     // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class
     // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled
     // in android_media_AudioTrack_native_write_byte()
-    if ((audioFormat == javaAudioTrackFields.PCM8)
+    if ((audioFormat == ENCODING_PCM_8BIT)
         && (memoryMode == MODE_STATIC)) {
         ALOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \
             buff size of %dbytes, switching to 16bit, buff size of %dbytes",
             buffSizeInBytes, 2*buffSizeInBytes);
-        audioFormat = javaAudioTrackFields.PCM16;
+        audioFormat = ENCODING_PCM_16BIT;
         // we will need twice the memory to store the data
         buffSizeInBytes *= 2;
     }
 
     // compute the frame count
-    int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
-    audio_format_t format = audioFormat == javaAudioTrackFields.PCM16 ?
+    int bytesPerSample = audioFormat == ENCODING_PCM_16BIT ? 2 : 1;
+    audio_format_t format = audioFormat == ENCODING_PCM_16BIT ?
             AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT;
     int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
 
@@ -525,14 +519,14 @@
             written = 0;
         }
     } else {
-        if (audioFormat == javaAudioTrackFields.PCM16) {
+        if (audioFormat == ENCODING_PCM_16BIT) {
             // writing to shared memory, check for capacity
             if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
                 sizeInBytes = track->sharedBuffer()->size();
             }
             memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
             written = sizeInBytes;
-        } else if (audioFormat == javaAudioTrackFields.PCM8) {
+        } else if (audioFormat == ENCODING_PCM_8BIT) {
             // data contains 8bit data we need to expand to 16bit before copying
             // to the shared memory
             // writing to shared memory, check for capacity,
@@ -816,7 +810,7 @@
             sampleRateInHertz) != NO_ERROR) {
         return -1;
     }
-    return frameCount * nbChannels * (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1);
+    return frameCount * nbChannels * (audioFormat == ENCODING_PCM_16BIT ? 2 : 1);
 }
 
 // ----------------------------------------------------------------------------
@@ -890,8 +884,6 @@
 
 // field names found in android/media/AudioTrack.java
 #define JAVA_POSTEVENT_CALLBACK_NAME                    "postEventFromNative"
-#define JAVA_CONST_PCM16_NAME                           "ENCODING_PCM_16BIT"
-#define JAVA_CONST_PCM8_NAME                            "ENCODING_PCM_8BIT"
 #define JAVA_CONST_BUFFER_COUNT_NAME                    "BUFFER_COUNT"
 #define JAVA_CONST_STREAM_VOICE_CALL_NAME               "STREAM_VOICE_CALL"
 #define JAVA_CONST_STREAM_SYSTEM_NAME                   "STREAM_SYSTEM"
@@ -971,15 +963,6 @@
         ALOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
         return -1;
     }
-    if ( !android_media_getIntConstantFromClass(env, audioFormatClass,
-                JAVA_AUDIOFORMAT_CLASS_NAME,
-                JAVA_CONST_PCM16_NAME, &(javaAudioTrackFields.PCM16))
-           || !android_media_getIntConstantFromClass(env, audioFormatClass,
-                JAVA_AUDIOFORMAT_CLASS_NAME,
-                JAVA_CONST_PCM8_NAME, &(javaAudioTrackFields.PCM8)) ) {
-        // error log performed in android_media_getIntConstantFromClass()
-        return -1;
-    }
 
     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 8ef5d0b..5c8e010 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -55,9 +55,9 @@
 
     ScopedLocalRef<jobject> inputDeviceObj(env, env->NewObject(gInputDeviceClassInfo.clazz,
             gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
-            nameObj.get(), descriptorObj.get(), deviceInfo.isExternal(),
-            deviceInfo.getSources(), deviceInfo.getKeyboardType(),
-            kcmObj.get(), deviceInfo.hasVibrator()));
+             deviceInfo.getControllerNumber(), nameObj.get(), descriptorObj.get(),
+            deviceInfo.isExternal(), deviceInfo.getSources(), deviceInfo.getKeyboardType(),
+            kcmObj.get(), deviceInfo.hasVibrator(), deviceInfo.hasButtonUnderPad()));
 
     const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (size_t i = 0; i < ranges.size(); i++) {
@@ -87,7 +87,8 @@
     gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
 
     GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
-            "<init>", "(IILjava/lang/String;Ljava/lang/String;ZIILandroid/view/KeyCharacterMap;Z)V");
+            "<init>",
+            "(IIILjava/lang/String;Ljava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZ)V");
 
     GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
             "addMotionRange", "(IIFFFFF)V");
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 842a7f7..bf6753d 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -107,7 +107,7 @@
         return NULL;
     }
 
-    sp<Surface> surface(new Surface(bufferProducer));
+    sp<Surface> surface(new Surface(bufferProducer, true));
     if (surface == NULL) {
         return NULL;
     }
@@ -143,7 +143,7 @@
     }
 
     sp<IGraphicBufferProducer> bq = st->getBufferQueue();
-    sp<Surface> surface(new Surface(bq));
+    sp<Surface> surface(new Surface(bq, true));
     if (surface == NULL) {
         jniThrowException(env, OutOfResourcesException, NULL);
         return 0;
@@ -319,7 +319,7 @@
     sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
     if (gbp != NULL) {
         // we have a new IGraphicBufferProducer, create a new Surface for it
-        sur = new Surface(gbp);
+        sur = new Surface(gbp, true);
         // and keep a reference before passing to java
         sur->incStrong(&sRefBaseOwner);
     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bfd7560..378bce6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1901,6 +1901,13 @@
         android:description="@string/permdesc_bindDeviceAdmin"
         android:protectionLevel="signature" />
 
+    <!-- Required to add or remove another application as a device admin.
+         <p/>Not for use by third-party apps. -->
+    <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
+        android:label="@string/permlab_manageDeviceAdmins"
+        android:description="@string/permdesc_manageDeviceAdmins"
+        android:protectionLevel="signature|system" />
+
     <!-- Allows low-level access to setting the orientation (actually
          rotation) of the screen.
          <p>Not for use by third-party applications. -->
@@ -2513,6 +2520,12 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.updates.CarrierProvisioningUrlsInstallReceiver" >
+            <intent-filter>
+                <action android:name="android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS" />
+            </intent-filter>
+        </receiver>
+
         <receiver android:name="com.android.server.updates.TZInfoInstallReceiver" >
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_TZINFO" />
diff --git a/core/res/res/layout/pin_challenge.xml b/core/res/res/layout/restrictions_pin_challenge.xml
similarity index 65%
copy from core/res/res/layout/pin_challenge.xml
copy to core/res/res/layout/restrictions_pin_challenge.xml
index 2cb14b4..954af92 100644
--- a/core/res/res/layout/pin_challenge.xml
+++ b/core/res/res/layout/restrictions_pin_challenge.xml
@@ -37,38 +37,13 @@
             android:text="@string/restr_pin_create_pin"
             android:textColor="?android:attr/textColorSecondary" />
 
-        <!-- TextView android:id="@+id/pin1_label"
-            style="?android:attr/textAppearanceSmall"
-            android:layout_marginBottom="16dp"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/restr_pin_enter_pin"
-            android:textColor="?android:attr/textColorSecondary" /-->
-
-        <EditText android:id="@+id/pin1_text"
+        <EditText android:id="@+id/pin_text"
             style="?android:attr/textAppearanceMedium"
             android:layout_marginBottom="16dp"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:hint="@string/restr_pin_enter_pin"
-            android:inputType="textPassword"
-            android:textColor="?android:attr/textColorPrimary" />
-
-        <!-- TextView android:id="@+id/pin2_label"
-            style="?android:attr/textAppearanceSmall"
-            android:layout_marginBottom="16dp"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/restr_pin_confirm_pin"
-            android:textColor="?android:attr/textColorSecondary" /-->
-
-        <EditText android:id="@+id/pin2_text"
-            style="?android:attr/textAppearanceMedium"
-            android:layout_marginBottom="16dp"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:hint="@string/restr_pin_confirm_pin"
-            android:inputType="textPassword"
+            android:inputType="numberPassword"
             android:textColor="?android:attr/textColorPrimary" />
 
         <TextView android:id="@+id/pin_error_message"
diff --git a/core/res/res/layout/pin_challenge.xml b/core/res/res/layout/restrictions_pin_setup.xml
similarity index 76%
rename from core/res/res/layout/pin_challenge.xml
rename to core/res/res/layout/restrictions_pin_setup.xml
index 2cb14b4..03ed696 100644
--- a/core/res/res/layout/pin_challenge.xml
+++ b/core/res/res/layout/restrictions_pin_setup.xml
@@ -37,38 +37,31 @@
             android:text="@string/restr_pin_create_pin"
             android:textColor="?android:attr/textColorSecondary" />
 
-        <!-- TextView android:id="@+id/pin1_label"
-            style="?android:attr/textAppearanceSmall"
-            android:layout_marginBottom="16dp"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/restr_pin_enter_pin"
-            android:textColor="?android:attr/textColorSecondary" /-->
-
-        <EditText android:id="@+id/pin1_text"
+        <EditText android:id="@+id/pin_text"
             style="?android:attr/textAppearanceMedium"
             android:layout_marginBottom="16dp"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:hint="@string/restr_pin_enter_pin"
-            android:inputType="textPassword"
+            android:hint="@string/restr_pin_enter_old_pin"
+            android:inputType="numberPassword"
             android:textColor="?android:attr/textColorPrimary" />
 
-        <!-- TextView android:id="@+id/pin2_label"
-            style="?android:attr/textAppearanceSmall"
+        <EditText android:id="@+id/pin_new_text"
+            style="?android:attr/textAppearanceMedium"
             android:layout_marginBottom="16dp"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="@string/restr_pin_confirm_pin"
-            android:textColor="?android:attr/textColorSecondary" /-->
+            android:hint="@string/restr_pin_enter_new_pin"
+            android:inputType="numberPassword"
+            android:textColor="?android:attr/textColorPrimary" />
 
-        <EditText android:id="@+id/pin2_text"
+        <EditText android:id="@+id/pin_confirm_text"
             style="?android:attr/textAppearanceMedium"
             android:layout_marginBottom="16dp"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:hint="@string/restr_pin_confirm_pin"
-            android:inputType="textPassword"
+            android:inputType="numberPassword"
             android:textColor="?android:attr/textColorPrimary" />
 
         <TextView android:id="@+id/pin_error_message"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 3d6d9da..3c36cba 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Laat die program toe om take na die voorgrond of agtergrond te skuif. Die program kan dit moontlik sonder jou insette doen."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"stop lopende programme"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Laat die program toe om take te verwyder en hul programme te dood. Kwaadwillige programme kan die gedrag van ander programme ontwrig."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"bestuur aktiwiteitstapels"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Laat die program toe om by te voeg by die aktiwiteitstapels waarbinne ander programme loop, of dit te verwyder of te wysig. Kwaadwillige programme kan dalk die gedrag van ander programme ontwrig."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"begin enige aktiwiteit"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Laat die program toe om \'n aktiwiteit te begin, ongeag toestemming-beskerming of uitgevoerde status."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"stel skermversoenbaarheid"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n invoermetode te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"verbind aan \'n toeganklikheidsdiens"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Dit laat die houer toe om aan die top-koppelvlak van \'n toeganklikheidsdiens te verbind. Behoort nooit vir gewone programme nodig te wees nie."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"verbind aan \'n drukdiens"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Laat die houer toe om aan die top-koppelvlak van \'n drukdiens te verbind. Behoort nooit vir gewone programme nodig te wees nie."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"kry toegang tot alle druktake"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Gee die houer toegang tot druktake wat deur \'n ander program geskep is. Behoort nooit vir normale programme nodig te wees nie."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bind aan \'n teksdiens"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n teksdiens (bv SpellCheckerService) te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind aan \'n VPN-diens"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Laat die program toe om SurfaceFlinger se laevlak-kenmerke te gebruik."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lees raambuffer"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Laat die program toe om die inhoud van die raambuffer te lees."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"kry toegang tot InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Laat die program toe om InputFlinger se laevlak-kenmerke te gebruik."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"stel Wi-Fi-skerms op"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Laat die program toe om Wi-Fi-skerms op te stel en daaraan te koppel."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"beheer Wi-Fi-skerms"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Laat die program toe om netwerkbeleide te bestuur en program-spesifieke reëls te definieer."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verander verrekening van netwerkgebruik"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Laat die program toe om te verander hoe netwerkgebruik teenoor programme gemeet word. Nie vir gebruik deur normale programme nie."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"wysig sokmerke"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Laat die program toe om sokmerke vir roetering te wysig"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"kry toegang tot kennisgewings"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind aan \'n kennisgewingluisteraardiens"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Laat die houer toe om aan die top-koppelvlak van \'n kennisgewingluisteraardiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"roep die opstellingprogram op wat deur die draer voorsien is"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Laat die houer toe om die opstellingsprogram wat deur die draer voorsien is, op te roep. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,56 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Hierdie program werk nie met rekeninge vir beperkte profiele nie"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Geen program gevind om hierdie handeling te hanteer nie"</string>
     <string name="revoke" msgid="5404479185228271586">"Herroep"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Gekanselleer"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Kon nie inhoud skryf nie"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Voer PIN in"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Huidige PIN"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Nuwe PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Bevestig nuwe PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Skep \'n PIN vir wysigingbeperkings"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN\'e kom nie ooreen nie. Probeer weer."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN is te kort. Moet ten minste 4 syfers wees."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Verkeerde PIN. Probeer weer na 1 sekonde."</item>
+    <item quantity="other" msgid="8030607343223287654">"Verkeerde PIN. Probeer weer na <xliff:g id="COUNT">%d</xliff:g> sekondes."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index e719f72..f3c3401 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"መተግበሪያው ተግባሮችን ወደ ቅድመ ገጹ እና ወደ ዳራው እንዲያንቀሳቅስ ይፈቅድለታል። መተግበሪያው ይህንን ያላንተ ግብዓት ሊያደርግ ይችላል።"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"የአሂድ ትግበራዎች አቁም"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"ተግባሮችን ለማስወገድ እና መተግበሪያዎቻቸውን ለመግደል ለመተግበሪያ ይፈቅዳል። ጎጂ የሆኑ መተግበሪያዎች የሌሎችን መተግበሪያዎችን ባህሪ ሊያውኩ ይችላሉ።"</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"የእንቅስቃሴ ቁልሎችን ማቀናበር"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"መተግበሪያው ሌሎች መተግበሪያዎች በሚያሄዱበት የእንቅስቃሴዎች ቁልሎችን እንዲያክል፣ እንዲያስወግድ እና እንዲቀይር ያስችለዋል። ተንኮል-አዘል መተግበሪያዎች የሌሎች መተግበሪያዎች ባህሪን ሊበጠብጡ ይችላሉ።"</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"ማንኛውም እንቅስቃሴ ጀምር"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"መተግበሪያው ማንኛውም እንቅስቃሴ፣ የፍቃድ ጥበቃም ሆነ ወደ ውጭ የተላከበት ሁኔታ ሳይታይ፣ እንዲጀምር ይፈቅድለታል።"</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"የማያ ገጽ ተኳኋኝነት መድብ"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ በይነገጽ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ከአንድ የተደራሽነት አገልግሎት ጋር እሰር"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"ያዢው ወደ የአንድ ተደራሽነት አገልግሎት ከፍተኛ-ደረጃ በይነገጽ እንዲያስር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች መቼም ቢሆን ሊያስፈልግ አይገባም።"</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"ከአንድ የህትመት አገልግሎት ጋር ማያያዝ"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"ያዢው የህትመት አገልግሎቱን ወደ ከፍተኛ-ደረጃ በይነገጽ እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"ሁሉንም የህትመት ስራዎችን መድረስ"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"ያዢው በሌላ መተግበሪያ የተፈጠሩ የህትመት ስራዎች እንዲደርስባቸው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"ለፅሁፍ አገልግሎት አሰረ"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"ያዡ ግቤት ለከፍተኛ-ደረጃ የፅሁፍ አገልግሎት ገፅታ ለመጠረዝ ይፈቅዳል። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"ለVPN አገልግሎት ተገዛ"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"መተግበሪያውን የSurfaceFlinger ዝቅተኛ ደረጃ ባህሪያትን ለመጠቀም ይፈቅዳል።"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"የንዑስ ክፈፍ ቋት አንብብ"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"የክፈፍ ቋት ይዘት ለማንበብ ለመተግበሪያው ይፈቅዳሉ።"</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger ን መድረስ"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"መተግበሪያው ባለአነስተኛ የInputFlinger ባህሪያት እንዲጠቀም ይፈቅድለታል።"</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"የWifi ማሳያዎችን አዋቅር"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"መተግበሪያው የWifi ማሳያዎችን እንዲያዋቅርና ከእነሱ ጋር እንዲገናኝ ይፈቅድለታል።"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"የWifi ማሳያዎችን ተቆጣጠር"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"የአውታረመረብ ቋሚ መመሪያዎችን እና ትግበራ ተኮር ደንቦችን ለማደራጀት ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"የአውታረ መረብ አጠቃቀም"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ከመተግበሪያዎች በተለየ መልኩ እንዴት የአውታረ መረብ አጠቃቀም እንደተመዘገበ ለመቀየር ለመተግበሪያው ይፈቅዳሉ።ለመደበኛ መተግበሪያዎች አገልግሎት አይውልም።"</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"የሶኬት ምልክቶችን መቀየር"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"መተግበሪያው መንገድ እንዲፈልግ የሶኬት ምልክቶቹን እንዲቀይር ያስችለዋል"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"ማሳወቂያዎችን ይድረሱ"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን መጥራት"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ድንቦች አዘጋጅ"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"ይህ መተግበሪያ የተገደቡ መገለጫዎች መለያዎችን አይደግፍም"</string>
     <string name="app_not_found" msgid="3429141853498927379">"ይህን እርምጃ የሚያከናውን ምንም መተግበሪያ አልተገኘም"</string>
     <string name="revoke" msgid="5404479185228271586">"ሻር"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"አይ ኤስ ኦ ኤ0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"አይ ኤስ ኦ ኤ1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"አይ ኤስ ኦ ኤ2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"አይ ኤስ ኦ ኤ3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"አይ ኤስ ኦ ኤ4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"አይ ኤስ ኦ ኤ5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"አይ ኤስ ኦ ኤ6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"አይ ኤስ ኦ ኤ7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"አይ ኤስ ኦ ኤ8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"አይ ኤስ ኦ ኤ9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"አይ ኤስ ኦ ኤ10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"አይ ኤስ ኦ ቢ0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"አይ ኤስ ኦ ቢ1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"አይ ኤስ ኦ ቢ2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"አይ ኤስ ኦ ቢ3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"አይ ኤስ ኦ ቢ4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"አይ ኤስ ኦ ቢ5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"አይ ኤስ ኦ ቢ6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"አይ ኤስ ኦ ቢ7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"አይ ኤስ ኦ ቢ8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"አይ ኤስ ኦ ቢ9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"አይ ኤስ ኦ ቢ10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"አይ ኤስ ኦ ሲ0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"አይ ኤስ ኦ ሲ1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"አይ ኤስ ኦ ሲ2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"አይ ኤስ ኦ ሲ3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"አይ ኤስ ኦ ሲ4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"አይ ኤስ ኦ ሲ5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"አይ ኤስ ኦ ሲ6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"አይ ኤስ ኦ ሲ7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"አይ ኤስ ኦ ሲ8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"አይ ኤስ ኦ ሲ9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"አይ ኤስ ኦ ሲ10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"ደብዳቤ"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"የመንግስት ደብዳቤ"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"ሕግ"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"ጁኒየር ህጋዊ"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"የሒሳብ መዝገብ"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"ታብሎይድ"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ተትቷል"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"ይዘት መጻፍ ላይ ስህተት"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"ፒን ያስገቡ"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"ገደቦችን ለመቀየር ፒን ይፍጠሩ"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"ፒኖች አይዛመዱም። እንደገና ይሞክሩ።"</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"ፒን በጣም አጭር ነው። ቢያንስ 4 አኃዝ መሆን አለበት።"</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"ትክክል ያልሆነ ፒን። በ1 ሰከንድ ውስጥ እንደገና ይሞክሩ።"</item>
+    <item quantity="other" msgid="8030607343223287654">"ትክክል ያልሆነ ፒን። በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ።"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 88c55c5..2df723a 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"للسماح للتطبيق بنقل المهام إلى المقدمة والخلفية. وقد يجري التطبيق ذلك بدون إذنك."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"إيقاف التطبيقات التي قيد التشغيل"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"للسماح للتطبيق بإزالة المهام وإنهاء تطبيقاتها. قد تعطل التطبيقات الضارة عمل التطبيقات الأخرى."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"إدارة حزم الأنشطة"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"للسماح للتطبيق بإضافة حزم الأنشطة التي تعمل بها التطبيقات الأخرى وإزالتها وتعديلها. فقد تعطل التطبيقات الضارة سلوك عمل التطبيقات الأخرى."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"بدء أي نشاط"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"للسماح للتطبيق ببدء أي نشاط، بغض النظر عن حماية الإذن أو حالة التصدير."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تعيين توافق الشاشة"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لأسلوب الإدخال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"الالتزام بخدمة إمكانية الدخول"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة إمكانية الدخول. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"الالتزام بخدمة طباعة"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الطباعة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"الدخول إلى جميع وظائف الطباعة"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"للسماح للمالك بالدخول إلى وظائف الطباعة التي أنشأها تطبيق آخر. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"الالتزام بخدمة إدخال النصوص"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة إدخال النصوص (على سبيل المثال، SpellCheckerService). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"الالتزام بخدمة VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"للسماح للتطبيق باستخدام ميزات SurfaceFlinger ذات المستوى المنخفض."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"قراءة المخزن المؤقت للإطارات"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"للسماح للتطبيق بقراءة محتوى المخزن المؤقت للإطارات."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"الدخول إلى InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"للسماح للتطبيق باستخدام ميزات InputFlinger ذات المستوى المنخفض."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"تهيئة شاشات Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"للسماح للتطبيق بتهيئة شاشات Wi-Fi والاتصال بها."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"التحكم في شاشات Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"للسماح لتطبيق بإدارة سياسات الشبكة وتحديد قواعد متعلقة بالتطبيق."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"تعديل حساب استخدام الشبكة"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"للسماح للتطبيق بتعديل كيفية حساب استخدام الشبكة في التطبيقات. ليس للاستخدام بواسطة التطبيقات العادية."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"تعديل علامات المقابس"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"للسماح للتطبيق بتعديل علامات المقابس لإعادة التوجيه."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"إشعارات الدخول"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"استدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"للسماح للمالك باستدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"لا يتوافق هذا التطبيق مع حسابات الملفات الشخصية المقيدة"</string>
     <string name="app_not_found" msgid="3429141853498927379">"لم يتم العثور على تطبيق يمكنه التعامل مع هذا الإجراء."</string>
     <string name="revoke" msgid="5404479185228271586">"إلغاء"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"ملغاة"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"حدث خطأ أثناء كتابة المحتوى"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"إدخال رقم التعريف الشخصي"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"إنشاء رقم تعريف شخصي لتعديل القيود"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"أرقام التعريف الشخصية لا تتطابق، أعد المحاولة."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"رقم التعريف الشخصي أقصر مما يلزم، يجب ألا يقل عن 4 أرقام. "</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"رقم التعريف الشخصي غير صحيح، الرجاء إعادة المحاولة بعد ثانية واحدة."</item>
+    <item quantity="other" msgid="8030607343223287654">"رقم التعريف الشخصي غير صحيح، الرجاء إعادة المحاولة بعد <xliff:g id="COUNT">%d</xliff:g> من الثواني."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index d6997f0..c2ffeb3 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1610,11 +1610,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8d0826c..15ecdc2 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index bc7b539..494457c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permet que l\'aplicació desplaci tasques en primer o segon pla. L\'aplicació pot fer-ho sense que tu ho indiquis."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"atura les aplicacions que s\'estan executant"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet que l\'aplicació elimini tasques i finalitzi les seves aplicacions. Les aplicacions malicioses poden alterar el comportament d\'altres aplicacions."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gestiona les piles d\'activitats"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permet que l\'aplicació, afegeixi, suprimeixi i modifiqui les piles d\'activitats on s\'executen altres aplicacions. És possible que les aplicacions malicioses interrompin el comportament d\'altres aplicacions."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar qualsevol activitat"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permet que l\'aplicació iniciï qualsevol activitat, amb independència de la protecció del permís o de l\'estat exportat."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definició de la compatibilitat de pantalla"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permet que el titular vinculi a la interfície de nivell superior d\'un mètode d\'entrada. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular amb un servei d\'accessibilitat"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permet vincular amb la interfície de nivell superior d\'un servei d\'accessibilitat. Les aplicacions normals no haurien de necessitar-ho."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"vincula amb un servei d\'impressió"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei d\'impressió. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"accedeix a totes les tasques d\'impressió"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permet que el propietari accedeixi a les tasques d\'impressió creades per una altra aplicació. Les aplicacions normals no l\'haurien de necessitar mai."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vincula a un servei de text"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permet al titular vincular amb la interfície de nivell superior d\'un servei de text (per exemple, SpellCheckerService). Les aplicacions normals mai no ho haurien de necessitar."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincula a un servei de VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permet que l\'aplicació utilitzi funcions SurfaceFlinger de baix nivell."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"llegir la memòria intermèdia de marcs"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permet que l\'aplicació llegeixi el contingut de la memòria intermèdia de marcs."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"accedeix a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permet que l\'aplicació utilitzi funcions InputFlinger de baix nivell."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configuració de les pantalles Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permet a l\'aplicació configurar-se i connectar-se a les pantalles Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"control de les pantalles Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet que l\'aplicació gestioni les polítiques de la xarxa i que defineixi les regles específiques d\'aplicació."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificació del càlcul d\'ús de la xarxa"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet que l\'aplicació modifiqui la manera com es calcula l\'ús de la xarxa per part de les aplicacions. No indicat per a les aplicacions normals."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modifica les marques dels sòcols"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permet que l\'aplicació modifiqui les marques de sòcols per a l\'encaminament"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei de processament de notificacions"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei de processament de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoca l\'aplicació de configuració proporcionada per l\'operador"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet que el titular invoqui l\'aplicació de configuració proporcionada per l\'operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Defineix les normes de contrasenya"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control d\'intents de desbloqueig de pantalla"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"L\'aplicació no és compatible amb comptes de perfils restringits"</string>
     <string name="app_not_found" msgid="3429141853498927379">"No s\'ha trobat cap aplicació per processar aquesta acció"</string>
     <string name="revoke" msgid="5404479185228271586">"Revoca"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Carta"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Carta governamental"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Legal Junior"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Llibre major"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloide"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancel·lada"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error en escriure el contingut"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introdueix el PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crea un pin per modificar les restriccions"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Els PIN no coincideixen. Torna-ho a provar."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN és massa curt. Ha de tenir quatre dígits com a mínim."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN incorrecte. Torna-ho a provar d\'aquí a 1 segon."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN incorrecte. Torna-ho a provar d\'aquí a <xliff:g id="COUNT">%d</xliff:g> segons."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 7805977..7f7700a 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Umožňuje aplikaci přesunout úlohy na popředí nebo pozadí. Aplikace tak může činit bez vašeho zásahu."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zastavení činnosti aplikací"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikaci odstranit úlohy a ukončit jejich aplikace. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"spravovat zásobníky aktivit"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Umožňuje aplikaci přidat, odstranit nebo upravit zásobníky aktivit jiných aplikací. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"zahájení libovolné činnosti"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Umožňuje aplikaci zahájit libovolnou aktivitu bez ohledu na ochranu pomocí oprávnění či exportovaný stav."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavit kompatibilitu obrazovky"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Umožňuje držiteli vázat se na nejvyšší úroveň rozhraní pro zadávání dat. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"navázat se na službu usnadnění přístupu"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby usnadnění přístupu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"navázat se na tiskovou službu"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Umožňuje navázání na nejvyšší úroveň tiskové služby. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"přístup ke všem tiskovým úlohám"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Umožňuje přístup k tiskovým úlohám vytvořeným jinou aplikací. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"navázat se na textovou službu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Umožňuje držiteli připojit se k nejvyšší úrovni rozhraní textové služby (např. SpellCheckerService). Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"navázat se na službu VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikaci používat nízkoúrovňové funkce SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čtení vyrovnávací paměti snímků"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Umožňuje aplikaci číst obsah vyrovnávací paměti snímků."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"přístup k funkci InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Umožňuje aplikaci používat nízkoúrovňové funkce InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurovat displeje přes Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Povoluje aplikaci připojit a konfigurovat displeje přes Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ovládat displeje přes Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikaci spravovat zásady sítě a definovat pravidla pro konkrétní aplikace."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"upravit kontrolu používání sítě"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikaci upravit způsob výpočtu využití sítě aplikacemi. Toto oprávnění není určeno pro běžné aplikace."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"upravit značky soketů"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Umožňuje aplikaci upravit značky soketů pro směrování"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"přístup k oznámením"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"navázání na službu pro poslouchání oznámení"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteli navázat se na nejvyšší úroveň služby pro poslouchání oznámení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolat konfigurační aplikaci poskytnutou operátorem"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje vyvolání konfigurační aplikace poskytnuté operátorem. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Tato aplikace nepodporuje účty pro omezené profily"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Aplikace potřebná k provedení této akce nebyla nalezena"</string>
     <string name="revoke" msgid="5404479185228271586">"Zrušit"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Zrušeno"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Při zápisu obsahu došlo k chybě"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Zadejte kód PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Vytvořit kód PIN pro úpravy omezení"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN se neshodují. Zkuste to znovu."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je příliš krátký. Musí mít alespoň čtyři číslice."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Nesprávný kód PIN. Zkuste to znovu za jednu sekundu."</item>
+    <item quantity="other" msgid="8030607343223287654">"Nesprávný kód PIN. Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 5bb2ae8..cc796b6 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Tillader, at appen kan flytte opgaver til forgrunden og baggrunden. Appen kan gøre dette uden din bekræftelse."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"stoppe kørsel af apps"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillader, at en app kan fjerne opgaver og lukke deres apps. Ondsindede apps kan forstyrre adfærden for andre apps."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrere aktivitetsstakke"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Tillader, at appen tilføjer, fjerner og ændrer aktivitetsstakkene, hvori andre apps kører. Skadelige apps kan forstyrre adfærden for andre apps."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"starte en aktivitet"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Tillader, at appen starter en hvilken som helst aktivitet, uanset tilladelsesbeskyttelse eller eksporteret tilstand."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"indstil skærmens kompatibilitet"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Tillader, at brugeren kan forpligter sig til en inputmetodes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind dig til en tilgængelighedstjeneste"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Tillader, at brugeren binder sig til en grænseflade for en tilgængelighedstjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"forbinde til en udskriftstjeneste"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Tillader, at brugeren forbinder til grænsefladen for en udskriftstjeneste på øverste niveau. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"få adgang til alle udskriftsjob"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Tillader, at brugeren får adgang til udskriftsjob, der er oprettet af en anden app. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"forpligte sig til en sms-tjeneste"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Tillader, at ejeren kan binde en teksttjenestes grænseflade (f. eks. SpellCheckerService) på øverste niveau. Dette bør aldrig være nødvendigt til normale apps."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind til en VPN-tjeneste"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Tillader, at appen kan bruge SurfaceFlinger-funktioner på lavt niveau."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"læs rammebuffer"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Tillader, at appen kan læse indholdet fra rammebufferen."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"få adgang til InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Giver appen tilladelse til at bruge SurfaceFlinger-funktioner på lavt niveau."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurer Wi-Fi-skærme"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillader, at appen konfigurerer og opretter forbindelse til Wi-Fi-skærme."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollér Wi-Fi-skærme"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"skift afregning af netværksbrug"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"ændre socketmærker"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Tillader, at appen ændrer socketmærker ved omdirigering"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, herunder dem, der er sendt af andre apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"aktivere konfigurationsappen, der leveres af mobilselskabet"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Tillader, at brugeren aktiverer konfigurationsappen, der er ydet af mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Denne applikation understøtter ikke konti for begrænsede profiler"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Der blev ikke fundet nogen applikation, der kan håndtere denne handling"</string>
     <string name="revoke" msgid="5404479185228271586">"Tilbagekald"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Amerikansk \"Letter\""</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Amerikansk \"Government Letter\""</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Amerikansk \"Legal\""</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Amerikansk \"Junior Legal\""</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Amerikansk \"Ledger\""</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Amerikansk \"Tabloid\""</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Annulleret"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fejl ved skrivning af indhold"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Indtast pinkode"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Opret en pinkode til ændring af begrænsninger"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Pinkoderne stemmer ikke overens. Prøv igen."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pinkoden er for kort. Den skal være på mindst 4 tal."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Forkert pinkode. Prøv igen om 1 sekund."</item>
+    <item quantity="other" msgid="8030607343223287654">"Forkert pinkode. Prøv igen om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 7716e84..729ce6c 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ermöglicht der App, Aufgaben in den Vorder- und Hintergrund zu verschieben, ohne dass dazu ein Eingreifen Ihrerseits notwendig ist."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"Aktive Apps beenden"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Ermöglicht der App, Aufgaben zu entfernen und die entsprechenden Apps zu beenden. Schädliche Apps können das Verhalten anderer Apps stören."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"Aktivitätsstapel verwalten"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Ermöglicht der App das Hinzufügen, Entfernen und Ändern der Aktivitätsstapel, in denen andere Apps ausgeführt werden. Schädliche Apps können das Verhalten anderer Apps beeinträchtigen."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"Beliebige Aktivität starten"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Ermöglicht der App, ungeachtet der Berechtigungen oder des Exportstatus beliebige Aktivitäten zu starten"</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Bildschirmkompatibilität festlegen"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ermöglicht dem Halter, sich an die Oberfläche einer Eingabemethode auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"An eine Bedienungshilfe binden"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ermöglicht dem Halter, sich an die Oberfläche einer Bedienungshilfe auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"An einen Druckdienst binden"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Druckdienstes auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"Auf alle Druckaufträge zugreifen"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Ermöglicht dem Inhaber den Zugriff auf von einer anderen App erstellte Druckaufträge. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"An einen Textdienst binden"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ermöglicht dem Halter, sich an die Oberfläche eines Textdienstes auf oberster Ebene zu binden, z. B. eines Rechtschreibprüfungsdienstes. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"An einen VPN-Dienst binden"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ermöglicht der App, die systemnahen SurfaceFlinger-Funktionen zu verwenden"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Frame-Puffer lesen"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ermöglicht der App, den Inhalt des Frame-Puffers zu lesen"</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"Auf InputFlinger zugreifen"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Ermöglicht der App, die systemnahen InputFlinger-Funktionen zu verwenden"</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"WLAN-Anzeigen konfigurieren"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Erlaubt der App, WLAN-Anzeigen zu konfigurieren und eine Verbindung zu diesen herzustellen"</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"WLAN-Anzeigen steuern"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ermöglicht der App, Netzwerkrichtlinien zu verwalten und anwendungsspezifische Regeln festzulegen"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Zuordnung für Netzwerknutzung ändern"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ermöglicht der App, die Art und Weise zu ändern, wie der Netzwerkverbrauch im Hinblick auf Apps berechnet wird. Nicht für normale Apps vorgesehen."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"Socket-Markierungen ändern"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Ermöglicht der App das Ändern von Socket-Markierungen für das Routing"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"Auf Benachrichtigungen zugreifen"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"An Benachrichtigungs-Listener-Dienst binden"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ermöglicht dem Inhaber, sich an die Oberfläche der obersten Ebene eines Benachrichtigungs-Listener-Dienstes zu binden. Sollte nie für normale Apps benötigt werden."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufrufen"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Inhaber, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo!"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Diese App unterstützt keine Konten für eingeschränkte Profile."</string>
     <string name="app_not_found" msgid="3429141853498927379">"Für diese Aktion wurde keine App gefunden."</string>
     <string name="revoke" msgid="5404479185228271586">"Aufheben"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Abgebrochen"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fehler beim Schreiben von Inhalten"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN eingeben"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"PIN für das Ändern von Einschränkungen erstellen"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuchen Sie es erneut."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Die PIN ist zu kurz. Sie muss mindestens vier Ziffern umfassen."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Falsche PIN. In 1 Sek. erneut versuchen."</item>
+    <item quantity="other" msgid="8030607343223287654">"Falsche PIN. In <xliff:g id="COUNT">%d</xliff:g> Sek. erneut versuchen."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index fecbaaa..6c05796 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Επιτρέπει στην εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και το παρασκήνιο. Η εφαρμογή μπορεί να το κάνει αυτό χωρίς να καταχωρίσετε δεδομένα εισόδου."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"διακοπή εκτέλεσης εφαρμογών"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Επιτρέπει στην εφαρμογή την κατάργηση ενεργειών και την απομάκρυνση των εφαρμογών τους. Τυχόν κακόβουλες εφαρμογές ενδέχεται να διαταράξουν τη λειτουργία άλλων εφαρμογών."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"διαχείριση στοιβών δραστηριότητας"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Επιτρέπει στην εφαρμογή την προσθήκη, την κατάργηση και την τροποποίηση των στοιβών δραστηριότητας στις οποίες εκτελούνται άλλες εφαρμογές. Οι κακόβουλες εφαρμογές ενδέχεται να προκαλέσουν προβλήματα στη συμπεριφορά άλλων συσκευών."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"έναρξη οποιασδήποτε δραστηριότητας"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Επιτρέπει στην εφαρμογή την έναρξη οποιασδήποτε δραστηριότητας, ανεξάρτητα από την προστασία αδειών ή την κατάσταση εξαγωγής."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ρύθμιση συμβατότητας οθόνης"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας μεθόδου εισόδου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"δέσμευση σε υπηρεσία προσβασιμότητας"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανώτατου επιπέδου μιας υπηρεσίας προσβασιμότητας. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"δέσμευση σε υπηρεσία εκτύπωσης"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας εκτύπωσης. Δεν απαιτείται για κανονικές εφαρμογές."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"πρόσβαση σε όλες τις εργασίες εκτύπωσης"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Επιτρέπει στον κάτοχο να αποκτά πρόσβαση σε εργασίες εκτύπωσης από άλλες εφαρμογές. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"δέσμευση σε υπηρεσία ανταλλαγής μηνυμάτων"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Επιτρέπει στον κάτοχο τη σύνδεση με τη διεπαφή ανωτέρου επιπέδου μιας υπηρεσίας ανταλλαγής μηνυμάτων (π.χ. SpellCheckerService). Δεν είναι απαραίτητο για κανονικές εφαρμογές."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"δέσμευση σε υπηρεσία VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Επιτρέπει σε μια εφαρμογή να χρησιμοποιεί λειτουργίες SurfaceFlinger χαμηλού επιπέδου."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ανάγνωση προσωρινής μνήμης πλαισίου"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Επιτρέπει στην εφαρμογή την ανάγνωση του περιεχομένου της προσωρινής μνήμης πλαισίου."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"πρόσβαση στο InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Επιτρέπει σε μια εφαρμογή να χρησιμοποιεί λειτουργίες InputFlinger χαμηλού επιπέδου."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"διαμόρφωση οθονών Wifi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Επιτρέπει τη διαμόρφωση της εφαρμογής και τη σύνδεσης σε οθόνες Wifi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"έλεγχος οθονών Wifi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Επιτρέπει στην εφαρμογή τη διαχείριση των πολιτικών δικτύου και τον ορισμό κανόνων για ορισμένες εφαρμογές."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποίηση υπολογισμού χρήσης δικτύου"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"τροποποίηση σημείων υποδοχής"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Επιτρέπει στην εφαρμογή την τροποποίηση σημείων υποδοχής για δρομολόγηση"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Αυτή η εφαρμογή δεν υποστηρίζει λογαριασμούς για περιορισμένα προφίλ"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Δεν υπάρχει εφαρμογή για τη διαχείριση αυτής της ενέργειας"</string>
     <string name="revoke" msgid="5404479185228271586">"Ανάκληση"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Επιστολή"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Κρατική επιστολή"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Νομικό"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Λογιστικό"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Ακυρώθηκε"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Σφάλμα κατά την εγγραφή περιεχομένου"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Εισαγωγή PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Δημιουργία PIN για τροποποίηση περιορισμών"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Τα PIN δεν συμφωνούν. Προσπαθήστε ξανά."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Το PIN είναι υπερβολικά μικρό. Πρέπει να έχει μέγεθος τουλάχιστον 4 χαρακτήρων."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Εσφαλμένο PIN. Προσπαθήστε ξανά σε 1 δευτερόλεπτο."</item>
+    <item quantity="other" msgid="8030607343223287654">"Εσφαλμένο PIN. Προσπαθήστε ξανά σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 63d5f66..acb4b35 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Allows the app to move tasks to the foreground and background. The app may do this without your input."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"stop running apps"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Allows the app to remove tasks and kill their apps. Malicious apps may disrupt the behaviour of other apps."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"manage activity stacks"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Allows the app to add, remove and modify the activity stacks in which other apps run. Malicious apps may disrupt the behaviour of other apps."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"start any activity"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Allows the app to start any activity, regardless of permission protection or exported state."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"set screen compatibility"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Allows the holder to bind to the top-level interface of an input method. Should never be needed for normal apps."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"bind to an accessibility service"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Allows the holder to bind to the top-level interface of an accessibility service. Should never be needed for normal apps."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"bind to a print service"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Allows the holder to bind to the top-level interface of a print service. Should never be needed for normal apps."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"access all print jobs"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Allows the holder to access print jobs created by another app. Should never be needed for normal apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bind to a text service"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Allows the holder to bind to the top-level interface of a text service (e.g. SpellCheckerService). Should never be needed for normal applications."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind to a VPN service"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Allows the app to use SurfaceFlinger low-level features."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"read frame buffer"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Allows the app to read the content of the frame buffer."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"access InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Allows the app to use InputFlinger low-level features."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configure Wi-Fi displays"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Allows the app to configure and connect to Wi-Fi displays."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"control Wi-Fi displays"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Allows the app to manage network policies and define app-specific rules."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modify network usage accounting"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Allows the app to modify how network usage is accounted against apps. Not for use by normal apps."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modify socket marks"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Allows the app to modify socket marks for routing"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"access notifications"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoke the carrier-provided configuration app"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"Net Meeting"</string>
@@ -1527,98 +1514,56 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"This app doesn\'t support accounts for restricted profiles"</string>
     <string name="app_not_found" msgid="3429141853498927379">"No application found to handle this action"</string>
     <string name="revoke" msgid="5404479185228271586">"Revoke"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelled"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error writing content"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Enter PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Current PIN:"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"New PIN"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirm new PIN"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Create a PIN for modifying restrictions"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINs don\'t match. Try again."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN is too short. Must be at least 4 digits."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Incorrect PIN. Try again in 1 second."</item>
+    <item quantity="other" msgid="8030607343223287654">"Incorrect PIN. Try again in <xliff:g id="COUNT">%d</xliff:g> seconds."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 1eafed5..9fd6637 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que la aplicación mueva tareas a segundo o a primer plano. La aplicación puede utilizar este permiso para realizar estos movimientos sin indicártelo."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"detener las aplicaciones en ejecución"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación elimine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrar pilas de actividad"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que la aplicación agregue, elimine y modifique las pilas de actividad en las que se ejecutan otras aplicaciones. Las aplicaciones maliciosas pueden interrumpir el comportamiento de otras aplicaciones."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"Iniciar cualquier actividad"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite a la aplicación iniciar una actividad, sin importar si fue exportada ni si se encuentra protegida por permisos."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Definir compatibilidad de pantalla"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite al propietario vincularse a la interfaz de nivel superior de un método de entrada. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular a un servicio de accesibilidad"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de accesibilidad. Las aplicaciones normales no deberían necesitar este permiso."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"vincular a un servicio de impresión"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de impresión. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"acceder a todos los trabajos de impresión"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite al propietario acceder a trabajos de impresión creados con otra aplicación. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vincular a un servicio de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite al titular vincularse a la interfaz de nivel superior de un servicio de texto (p. ej., SpellCheckerService). Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincular con un servicio de VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que la aplicación utilice funciones de SurfaceFlinger de bajo nivel."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer el búfer de tramas"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite que la aplicación lea el contenido del búfer de tramas."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"acceder a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que la aplicación utilice funciones de InputFlinger de bajo nivel."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar pantallas Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que la aplicación configure y se conecte a pantallas Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar pantallas Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre las políticas de red y defina reglas específicas de la aplicación."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modificar la administración del uso de redes"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que la aplicación modifique marcas de socket para enrutamiento."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Vincular a un servicio de agente de escucha de notificaciones"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de agente de escucha de notificaciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el proveedor"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite al propietario ejecutar la aplicación de configuración proporcionada por el proveedor. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Esta aplicación no admite cuentas de perfiles restringidos."</string>
     <string name="app_not_found" msgid="3429141853498927379">"No se encontró una aplicación para manejar esta acción."</string>
     <string name="revoke" msgid="5404479185228271586">"Revocar"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelada"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error al escribir contenido"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Ingresar PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crear PIN para modificar restricciones"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Los PIN no coinciden. Vuelve a intentarlo."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN es demasiado corto. Debe tener al menos 4 dígitos."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Reintentar en 1 s"</item>
+    <item quantity="other" msgid="8030607343223287654">"Reintentar en <xliff:g id="COUNT">%d</xliff:g> s"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index dd4bac9..165c9b6 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que la aplicación mueva tareas a segundo o a primer plano. La aplicación puede utilizar este permiso para realizar estos movimientos sin que se lo indique el usuario."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"detener aplicaciones en ejecución"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación termine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrar pilas de actividad"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que la aplicación añada, elimine y modifique las pilas de actividad en las que se ejecutan otras aplicaciones. Las aplicaciones maliciosas pueden interrumpir el comportamiento de otras aplicaciones."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar una actividad"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite que la aplicación inicie una actividad, independientemente de la protección de permisos o de si está exportada."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"establecer compatibilidad de pantalla"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite que se enlace con la interfaz de nivel superior de un método de introducción de texto. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"enlazar con un servicio de accesibilidad"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite enlazar con la interfaz de nivel superior de un servicio de accesibilidad. Las aplicaciones normales no deberían necesitar este permiso."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"enlazar con un servicio de impresión"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite enlazar con la interfaz de nivel superior de un servicio de impresión. No debe ser necesario para las aplicaciones normales."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"acceder a todos los trabajos de impresión"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite acceder a trabajos de impresión creados con otra aplicación. No debe ser necesario para aplicaciones normales."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"enlazar con un servicio de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite enlazar con la interfaz de nivel superior de un servicio de texto (por ejemplo, SpellCheckerService). Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"enlazar con un servicio VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que la aplicación use funciones de SurfaceFlinger de nivel inferior."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer memoria de almacenamiento intermedio"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite que la aplicación lea el contenido de la memoria de almacenamiento intermedio."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"acceder a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que la aplicación utilice funciones de bajo nivel de SurfaceFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar pantallas Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que la aplicación configure pantallas Wi-Fi y se conecte a ellas."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar pantallas Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre políticas de red y defina reglas específicas de la aplicación."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar cálculo de uso de red"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que la aplicación modifique marcas de socket para enrutamiento"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"enlazar con un servicio de detector de notificaciones"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite enlazar con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el operador"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo!"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Conversaciones"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Esta aplicación no admite cuentas de perfiles restringidos"</string>
     <string name="app_not_found" msgid="3429141853498927379">"No se ha encontrado ninguna aplicación que pueda realizar esta acción."</string>
     <string name="revoke" msgid="5404479185228271586">"Revocar"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Carta"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Carta del gobierno"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Doble carta"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloide"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelado"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Error al escribir contenido"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introducir PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crear PIN para modificar restricciones"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Los números PIN no coinciden. Inténtalo de nuevo."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN es demasiado corto. Debe tener al menos 4 dígitos."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN incorrecto. Inténtalo de nuevo dentro de 1 segundo."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN incorrecto. Inténtalo de nuevo dentro de <xliff:g id="COUNT">%d</xliff:g> segundos."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index d5a8eed..82ea4a2 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6043d64..38bd3d6 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 744d818..dccf2ec 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 8e75805..86d0920 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 8c63d92..55c448a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"एप्लिकेशन को कार्यों को अग्रभूमि और पृष्‍ठभूमि पर ले जाने देता है. एप्लिकेशन आपके इनपुट के बिना यह कर सकता है."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्लिकेशन रोकें"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्‍लिकेशन को कार्यों को निकालने और उनके एप्‍लिकेशन समाप्त करने देता है. दुर्भावनापूर्ण एप्‍लिकेशन अन्‍य एप्‍लिकेशन का व्‍यवहार बाधित कर सकते हैं."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"गतिविधि स्टैक प्रबंधित करें"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"एप्लिकेशन को ऐसे गतिविधि स्टैक जोड़ने, निकालने, और बदलने देता है जिनमें अन्य एप्लिकेशन चलते हों. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन के व्यवहार में बाधा डाल सकते हैं."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"कोई गतिविधि प्रारंभ करें"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"अनुमति सुरक्षा या निर्यात की स्‍थिति पर ध्‍यान दिए बिना, एप्‍लिकेशन को कोई गतिविधि प्रारंभ करने देता है."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"स्‍क्रीन संगतता सेट करें"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"धारक को किसी इनपुट विधि के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"पहुंच-योग्‍यता सेवा से आबद्ध करें"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"धारक को किसी पहुंच-योग्यता सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"प्रिंट सेवा से आबद्ध करें"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"धारक को किसी प्रिंट सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"सभी प्रिंट कार्य एक्सेस करें"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"धारक को अन्य एप्लिकेशन के द्वारा बनाए गए प्रिंट कार्य एक्सेस करने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"किसी पाठ सेवा पर बने रहें"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"धारक को किसी पाठ सेवा (उदा. SpellCheckerService) के शीर्ष-स्‍तर इंटरफ़ेस पर आबद्ध होने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"किसी VPN सेवा से आबद्ध करें"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"एप्‍लिकेशन को SurfaceFlinger निम्‍न-स्‍तर सुविधाएं उपयोग करने देता है."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"फ़्रेम बफ़र पढ़ें"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"एप्‍लिकेशन को फ़्रेम बफ़र की सामग्री पढ़ने देता है."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger एक्सेस करें"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"एप्‍लिकेशन को InputFlinger निम्‍न-स्‍तर सुविधाओं का उपयोग करने देता है."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Wifi डिस्प्ले को कॉन्फ़िगर करें"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"एप्लिकेशन को कॉन्फ़िगर करने देता है और Wifi डिस्प्ले से कनेक्ट करता है."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Wifi डिस्प्ले को नियंत्रित करें"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्‍लिकेशन को नेटवर्क नीतियां प्रबंधित करने और एप्‍लिकेशन-विशिष्‍ट नियमों को परिभाषित करने देता है."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्लिकेशन को यह संशोधित करने देता है कि एप्‍लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्‍य एप्‍लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"सॉकेट मार्क बदलें"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"एप्लिकेशन को रूटिंग के लिए सॉकेट मार्क बदलने देता है"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्लिकेशन को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्लिकेशन के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्लिकेशन प्रारंभ करें"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन एप्लिकेशन प्रारंभ करने देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्‍क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"स्‍क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"यह एप्लिकेशन प्रतिबंधित प्रोफ़ाइल के खातों का समर्थन नहीं करता है"</string>
     <string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई एप्लिकेशन नहीं मिला"</string>
     <string name="revoke" msgid="5404479185228271586">"निरस्‍त करें"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"लेटर"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"गवर्नमेंट लेटर"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"लीगल"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"जूनियर लीगल"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"लेजर"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"टेबलॉइड"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"रद्द कर दी गई"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"सामग्री लिखने में त्रुटि"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN डालें"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"प्रतिबंधों को बदलने के लिए PIN बनाएं"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN मिलान नहीं करते हैं. पुनः प्रयास करें."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN बहुत छोटा है. कम से कम 4 अंकों का होना चाहिए."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"गलत PIN. 1 सेकंड में पुनः प्रयास करें."</item>
+    <item quantity="other" msgid="8030607343223287654">"गलत PIN. <xliff:g id="COUNT">%d</xliff:g> सेकंड में पुनः प्रयास करें."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0331bd8..50289a4 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Aplikaciji omogućuje premještanje zadataka u prednji plan ili pozadinu. Aplikacija to može napraviti bez vašeg naloga."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zaustavljanje pokrenutih aplikacija"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Omogućuje aplikaciji uklanjanje zadataka i uklanjanje njihovih aplikacija. Zlonamjerne aplikacije mogu poremetiti rad drugih aplikacija."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"upravljaj snopovima aktivnosti"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Dopušta aplikaciji dodavanje, uklanjanje i izmjenu snopova aktivnosti u kojima se druge aplikacije izvršavaju. Zlonamjerne aplikacije mogu poremetiti ponašanje ostalih aplikacija."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"započni bilo kakvu aktivnost"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Omogućuje aplikaciji da započne bilo koju aktivnost, bez obzira na zaštitu pomoću dozvola ili stanje izvoza."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje kompatibilnosti sa zaslonom"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Nositelju omogućuje povezivanje sučelja najviše razine načina unosa. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vezivanje uz uslugu dostupnosti"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge dostupnosti. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"veži se uz uslugu ispisa"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Dopušta nositelju vezanje uza sučelje usluge ispisa najviše razine. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"pristupi svim zadacima ispisa"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Dopušta nositelju pristup zadacima ispisa koje je izradila neka druga aplikacija. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vezanje na tekstualnu uslugu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Omogućuje korisniku povezivanje s najvišom razinom sučelja tekstualne usluge (npr. SpellCheckerService). Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vezanje na VPN uslugu"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Aplikaciji omogućuje upotrebu značajki niske razine SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čitanje međuspremnika okvira"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Aplikaciji omogućuje čitanje sadržaja međuspremnika okvira."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"pristupi InputFlingeru"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Dopušta aplikaciji upotrebu značajki niske razine InputFlingera."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfiguriraj Wifi zaslone"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Omogućuje aplikaciji konfiguriranje i povezivanje s Wi-Fi zaslonima."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"upravljaj Wifi zaslonima"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Aplikaciji omogućuje upravljanje mrežnim pravilima i određivanje pravila za aplikacije."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"izmjena evidencije mrežne upotrebe"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Omogućuje aplikaciji izmjenu načina upotrebe mreže u odnosu na aplikacije. Nije namijenjeno uobičajenim aplikacijama."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"izmijeni oznake utičnica"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Dopušta aplikaciji izmjenu oznaka utičnica za usmjeravanje"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"pristup obavijestima"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vezanje uz uslugu slušatelja obavijesti"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge slušatelja obavijesti. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"dozovi operaterovu aplikaciju za konfiguraciju"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Dopušta nositelju dozivanje operaterove aplikacije za konfiguraciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Aplikacija ne podržava račune za ograničene profile"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Nije pronađena aplikacija za upravljanje ovom radnjom"</string>
     <string name="revoke" msgid="5404479185228271586">"Opozovi"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Otkazano"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Pogreška prilikom pisanja sadržaja"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Unesite PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Izradite PIN za izmjenu ograničenja"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Pokušajte ponovo."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratak. Mora imati barem 4 znamenke."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN nije točan. Ponovite za 1 s."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN nije točan. Ponovite za <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 0e3359b..73d7341 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index c01df57..67e18542 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index b877501..7e106d8 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Consente all\'applicazione di spostare attività in primo piano e in background. L\'applicazione potrebbe farlo senza un tuo comando."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"interruzione applicazioni in esecuzione"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Consente all\'applicazione di rimuovere le attività e terminare le loro applicazioni. Le applicazioni dannose potrebbero interferire con il comportamento di altre applicazioni."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gestione di stack attività"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Consente all\'app di aggiungere, rimuovere e modificare stack attività in cui vengono eseguite altre app. Le app dannose possono alterare il funzionamento delle altre app."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"inizio di un\'attività"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Consente all\'applicazione di iniziare un\'attività, indipendentemente dalla protezione delle autorizzazioni o dallo stato esportato."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"impostazione compatibilità schermo"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Consente l\'associazione di un metodo di inserimento all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"collegamento a un servizio di accessibilità"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di accessibilità. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"collegamento a un servizio di stampa"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di stampa. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"accesso a tutti i processi di stampa"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Consente al titolare di accedere ai processi di stampa creati da un\'altra app. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"associazione a un servizio di testo"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di testo (ad esempio SpellCheckerService). Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"associazione a un servizio VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Consente all\'applicazione l\'utilizzo di funzioni di basso livello SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lettura buffer di frame"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Consente all\'applicazione di leggere i contenuti del buffer di frame."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"accesso a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Consente all\'applicazione di utilizzare funzioni di basso livello InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurazione di schermi Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Consente all\'applicazione di configurare schermi Wi-Fi e di collegarsi a essi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controllo di schermi Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Consente all\'applicazione di gestire le norme di rete e definire le regole specifiche delle applicazioni."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifica calcolo dell\'utilizzo della rete"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Consente all\'applicazione di modificare il calcolo dell\'utilizzo della rete tra le applicazioni. Da non usare per normali applicazioni."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modifica di contrassegni socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Consente all\'app di modificare i contrassegni socket per il routing"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesso a notifiche"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincolo a un servizio listener di notifica"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Consente al titolare di vincolarsi all\'interfaccia di primo livello di un servizio listener di notifica. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"richiamo dell\'app di configurazione operatore-provider"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Imposta regole password"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitora tentativi di sblocco dello schermo"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangout"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Questa app non supporta account relativi a profili con limitazioni"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Nessuna applicazione trovata in grado di gestire questa azione"</string>
     <string name="revoke" msgid="5404479185228271586">"Revoca"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Lettera"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legale"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Legale \"junior\""</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Annullato"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Errore nella scrittura dei contenuti"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Inserisci PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crea un PIN per la modifica delle limitazioni"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"I PIN non corrispondono. Riprova."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Il PIN è troppo corto. Deve avere almeno quattro cifre."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN errato. Riprova tra 1 s."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN errato. Riprova tra <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 11ff720..66a62e7 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"מאפשר ליישום להעביר משימות לחזית ולרקע. היישום עשוי לעשות זאת ללא התערבותך."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"עצירת יישומים פעילים"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"הרשאה זו מאפשרת ליישום להסיר משימות ולסגור את היישומים שבהם הן פועלות. יישומים זדוניים עלולים לשבש את פעולתם של יישומים אחרים."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"ניהול של ערימות פעילות"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"ההרשאה הזו מאפשרת לאפליקציה להוסיף, להסיר ולשנות את ערימות הפעילות שבהן רצות אפליקציות אחרות. אפליקציות זדוניות עלולת להפריע להתנהגות של אפליקציות אחרות."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"התחלת פעילות מכל סוג שהוא"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"מאפשר ליישום להתחיל בפעילות מכל סוג שהוא, ללא התחשבות בהגנת הרשאות או במצב מיוצא."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"הגדרת תאימות מסך"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שיטת קלט. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"הכפפה לשירות נגישות"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"מתיר לבעלים להכפיף לממשק ברמה העליונה של שירות זמינות. הרשאה זו אף פעם אינה אמורה להיות נחוצה ליישומים רגילים."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"איגוד לשירות הדפסה"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"ההרשאה הזו מאפשרת לבעלים לבצע איגוד לממשק הרמה העליונה של שירות הדפסה. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"גישה אל כל עבודות ההדפסה"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"ההרשאה הזו מאפשרת לבעלים לגשת לעבודות הדפסה שנוצרו על ידי אפליקציה אחרת. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"הכפפה לשירות טקסט"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"מאפשר למשתמש ליצור איגוד לממשק הרמה העליונה של שירות טקסט (למשל, SpellCheckerService). הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"אגד לשירות VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"מאפשר ליישום להשתמש בתכונות ברמה הנמוכה של SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"אחסון זמני של מסגרת קריאה"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"מאפשר ליישום לקרוא את התוכן של מאגר הנתונים הזמני של המסגרות."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"גישה אל InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"מאפשרת לאפליקציה להשתמש בתכונות ברמה נמוכה של InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"הגדר תצוגות Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"מאפשר לאפליקציה להגדיר ולהתחבר לתצוגות Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"שלוט בתצוגות Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"מאפשר ליישום לנהל מדיניות הרשת להגדיר כללים ספציפיים-ליישום."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"שנה ניהול חשבונות של שימוש ברשת"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"הרשאה זו מאפשרת ליישום לשנות את אופן החישוב של נתוני שימוש ברשת מול כל יישום. לא מיועד לשימוש ביישומים רגילים."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"שינוי של סימני Socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"ההרשאה הזו מאפשרת לאפליקציה לשנות סימני Socket עבור ניתוב"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"גישה להתראות"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר ליישום לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי יישומים אחרים."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה ליישומים רגילים."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"הפעלה של אפליקציית תצורה שסופקה על ידי ספק"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ההרשאה הזו מאפשרת לבעלים להפעיל את אפליקציית התצורה שסופקה על ידי ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,56 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"האפליקציה הזו לא תומכת בחשבונות עבור פרופילים מוגבלים"</string>
     <string name="app_not_found" msgid="3429141853498927379">"לא נמצא יישום שתומך בפעולה זו"</string>
     <string name="revoke" msgid="5404479185228271586">"בטל"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"בוטלה"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"שגיאה בכתיבת תוכן"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"הזן מספר PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"מספר PIN נוכחי"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"מספר PIN חדש"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"אשר את מספר ה-PIN החדש"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"צור מספר PIN לשינוי הגבלות"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"מספרי ה-PIN לא תואמים. נסה שוב."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"מספר ה-PIN קצר מדי. חייב להיות באורך 4 ספרות לפחות."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"מספר PIN שגוי. נסה שוב בעוד שניה."</item>
+    <item quantity="other" msgid="8030607343223287654">"מספר PIN שגוי. נסה שוב בעוד <xliff:g id="COUNT">%d</xliff:g> שניות."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 41c0021..9ed6742 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f079520..0375383 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 14d1af6..26d0cc7 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 7da9a73..aa7634e 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index e72085e..4602922 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 60a7bef..cab4cb1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Lar appen flytte oppgaver til forgrunnen eller bakgrunnen. Appen kan gjøre dette uten instruksjoner fra deg."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"avslutte apper som kjører"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Lar appen fjerne oppgaver og avslutte apper. Ondsinnede apper kan forstyrre atferden til andre apper."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"administrering av aktivitetsstabler"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Gir appen tillatelse til å legge til, fjerne og endre aktivitetsstablene som andre apper kjøres i. Skadelige apper kan skape problemer i atferden til andre apper."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"igangsetting av aktiviteter"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Tillater at appen kan starte en aktivitet, uavhengig av tillatelsesbeskyttelse og eksportstatus."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"angi skjermkompatibilitet"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lar innehaveren binde det øverste nivået av grensesnittet til en inndatametode. Skal aldri være nødvendig for normale apper."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"binde seg til en tilgjengelighetstjeneste"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Gir innehaveren tillatelse til å bindes til det øverste nivået av grensesnittet for en tilgjengelighetstjeneste. Skal aldri være nødvendig for vanlige apper."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"binding til en utskriftstjeneste"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en utskriftstjeneste. Dette skal ikke være nødvendig for vanlige apper."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"tilgang til alle utskriftsjobber"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Gir innehaveren tillatelse til å åpne utskriftsjobber som ble opprettet av andre apper. Dette skal ikke være nødvendig for vanlige apper."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"binde til en teksttjeneste"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Lar innehaveren binde seg til øverste grensesnittnivå for en teksttjeneste (f.eks. SpellCheckerService). Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"binde deg til en VPN-tjeneste"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Lar appen bruke grunnleggende SurfaceFlinger-funksjoner."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lese skjermbufferet"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Lar appen lese innholdet i rammebufferen."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"tilgang til InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Lar appen bruke grunnleggende InputFlinger-funksjoner."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurere Wi-Fi-skjermer"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Tillater appen å konfigurere og koble til Wi-Fi-skjermer."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"kontrollere Wi-Fi-skjermer"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lar appen administrere retningslinjene for nettverket og definere appspesifikke regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modifisering av regnskapsføring av nettverksbruk"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lar appen endre hvordan nettverksbruk regnes ut for apper. Ikke beregnet på vanlige apper."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"endring av kontaktmerker"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Gir appen tillatelse til å endre kontaktmerker for ruting"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"varseltilgang"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binding til en varsellyttertjeneste"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lar innehaveren binde seg til det øverste grensesnittnivået for en varsellyttertjeneste. Skal aldri være nødvendig for vanlige apper."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"anrop av konfigurasjonsappen som ble levert av operatøren"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Gir innehaveren tillatelse til å kalle opp den konfigurasjonsappen som ble levert av operatøren. Dette skal ikke være nødvendig for vanlige apper."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"OQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Denne appen støtter ikke kontoer for begrensede profiler"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Finner ingen apper som kan utføre denne handlingen"</string>
     <string name="revoke" msgid="5404479185228271586">"Opphev"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal (Nord-Amerika)"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Kansellert"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Feil under skriving av innhold"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Skriv inn PIN-koden"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Angi en PIN-kode for endring av begresninger"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-kodene stemmer ikke overens. Prøv på nytt."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-koden er for kort. Den må bestå av minst fire tegn."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Feil PIN-kode. Prøv på nytt om 1 sekund."</item>
+    <item quantity="other" msgid="8030607343223287654">"Feil PIN-kode. Prøv på nytt om <xliff:g id="COUNT">%d</xliff:g> sekunder."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1584122..b3fef17 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Hiermee kan de app taken naar de voor- en achtergrond verplaatsen. De app kan dit doen zonder om uw bevestiging te vragen."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"actieve apps stoppen"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Hiermee kan de app taken verwijderen en apps sluiten. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"activiteitstacks beheren"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Hiermee kan de app de activiteitstacks waarin andere apps worden uitgevoerd, toevoegen, verwijderen en aanpassen. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"elke activiteit starten"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Toestaan dat de app elke activiteit start, ongeacht rechtenbeveiliging of geëxporteerde status."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"schermcompatibiliteit instellen"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Hiermee kan de houder zich verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"koppelen aan een toegankelijkheidsservice"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een toegankelijkheidsservice. Nooit vereist voor normale apps."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"koppelen aan een afdrukservice"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Hiermee kan de houder verbinding maken met de hoofdinterface van een afdrukservice. Nooit vereist voor normale apps."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"toegang krijgen tot alle afdruktaken"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Hiermee kan de houder toegang krijgen tot afdruktaken die zijn gemaakt door een andere app. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"koppelen aan een sms-service"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Hiermee kan de gebruiker koppelen met de hoofdinterface van een tekstservice (zoals SpellCheckerService). Dit is niet nodig voor normale apps."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"koppelen aan een VPN-service"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Hiermee kan de app SurfaceFlinger-functies op laag niveau gebruiken."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"framebuffer lezen"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Hiermee kan de app de inhoud van de framebuffer lezen."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"toegang krijgen tot InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Hiermee kan de app InputFlinger-functies op laag niveau gebruiken."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"wifi-displays configureren"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"De app toestaan wifi-displays te configureren en hiermee verbinding te maken."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"wifi-displays beheren"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Hiermee kan de app het netwerkbeleid beheren en app-specifieke regels definiëren."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verrekening van netwerkgebruik aanpassen"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Hiermee kan een app aanpassen hoe het netwerkgebruik wordt toegekend aan apps. Dit wordt niet gebruikt door normale apps."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"socketmarkeringen aanpassen"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Hiermee kan de app socketmarkeringen voor routeren aanpassen"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"toegang tot meldingen"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"koppelen aan een listener-service voor meldingen"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Hiermee kan de houder koppelen aan de hoofdinterface van een listener-service voor meldingen. Nooit vereist voor normale apps."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"de door de provider geleverde configuratie-app aanroepen"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Hiermee kan de houder de door de provider geleverde configuratie-app aanroepen. Nooit vereist voor normale apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Deze app biedt geen ondersteuning voor accounts voor beperkte profielen"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Er is geen app gevonden om deze actie uit te voeren"</string>
     <string name="revoke" msgid="5404479185228271586">"Intrekken"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Geannuleerd"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van inhoud"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Geef de pincode op"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Maak een pincode voor het aanpassen van beperkingen"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"De pincodes komen niet overeen. Probeer het opnieuw."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pincode is te kort. Moet ten minste vier cijfers lang zijn."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Onjuiste pincode. Probeer het over één seconde opnieuw."</item>
+    <item quantity="other" msgid="8030607343223287654">"Onjuiste pincode. Probeer het over <xliff:g id="COUNT">%d</xliff:g> seconden opnieuw."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a56fdca..a6dfe94 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 61463d0..39bfbf2 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite que a aplicação mova tarefas para primeiro e segundo plano. A aplicação poderá fazê-lo sem qualquer entrada do utilizador."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"parar aplicações em execução"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que a aplicação remova tarefas e elimine as respetivas aplicações. As aplicações maliciosas podem perturbar o comportamento de outras aplicações."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gerir pilhas de atividade"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite que a aplicação adicione, remova e modifique as pilhas de atividade em que são executadas outras aplicações. As aplicações maliciosas podem afetar o comportamento de outras aplicações."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"iniciar qualquer atividade"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite que a aplicação inicie qualquer atividade, independentemente da proteção de permissão ou do estado exportado."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definir compatibilidade de ecrã"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite ao titular vincular-se à interface de nível superior de um método de entrada. Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"vincular a um serviço de acessibilidade"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite que o titular vincule a interface de nível superior de um serviço de acessibilidade. Nunca deverá ser necessário para aplicações normais."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"vincular a um serviço de impressão"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite que o titular vincule a interface de nível superior de um serviço de impressão. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"aceder a todas as tarefas de impressão"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite que o titular aceda a tarefas de impressão criadas por outra aplicação. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"vincular a um serviço de texto"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite ao titular ligar-se à interface de nível superior de um serviço de texto (por exemplo SpellCheckerService). Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"vincular a um serviço VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite à aplicação utilizar funcionalidades de SurfaceFlinger de nível inferior."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ler memória intermédia de fotogramas"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite à aplicação ler o conteúdo da memória intermédia de fotogramas."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"aceder a InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite que a aplicação utilize funcionalidades de InputFlinger de nível inferior."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurar visores Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite que a aplicação se configure e se ligue a visores Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlar visores Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que a aplicação faça a gestão de políticas de rede e defina regras específicas de aplicações."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contabilização da utilização da rede"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que a aplicação modifique o modo como a utilização da rede é contabilizada em relação a aplicações. Nunca é necessário para aplicações normais."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificar marcas de socket"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite que a aplicação modifique as marcas de socket para encaminhamento"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"aceder às notificações"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a um serviço de escuta de notificações"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o titular vincule a interface de nível superior de um serviço de escuta de notificações. Nunca deverá ser necessário para aplicações normais."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar a aplicação de configuração fornecida pela operadora"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o titular invoque a aplicação de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Esta aplicação não suporta contas de perfis restritos"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Não foram encontradas aplicações para executar esta ação"</string>
     <string name="revoke" msgid="5404479185228271586">"Revogar"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Cancelada"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Erro ao escrever conteúdo"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introduzir PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crie um PIN para modificar as restrições"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Os PINs não correspondem. Tente novamente."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"O PIN é demasiado pequeno. Deve ter, no mínimo, 4 dígitos."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN incorreto. Tente novamente em 1 seg."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN incorreto. Tente novamente em <xliff:g id="COUNT">%d</xliff:g> seg."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 70392c0..88460c4 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 06d0afb..66f68d0 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -2550,11 +2550,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 96c6f47..fda819d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 75d2e68..170e469 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 3806936..b300e9a 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Umožňuje aplikácii presunúť úlohy do popredia alebo do pozadia. Aplikácia tak môže urobiť bez vášho zásahu."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zastaviť spustené aplikácie"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikácii odstrániť úlohy a ukončiť ich aplikácie. Škodlivé aplikácie môžu narušiť správanie iných aplikácií."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"spravovanie zoskupení aktivít"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Umožňuje aplikácii pridať, odstrániť alebo upraviť zoskupenia aktivít, v ktorých sú spustené ostatné aplikácie. Škodlivé aplikácie môžu narušiť správanie ostatných aplikácií."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"spustiť ľubovoľnú aktivitu"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Umožňuje aplikácii spustiť ľubovoľnú aktivitu bez ohľadu na ochranu povolení alebo exportovaný stav."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastaviť kompatibilitu obrazovky"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania metódy vstupu. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"viazať na službu zjednodušeného ovládania"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby zjednodušeného ovládania. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"viazanie na tlačovú službu"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tlačovej služby. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"prístup ku všetkým tlačovým úlohám"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Umožňuje držiteľovi prístup k tlačovým úlohám vytvoreným inou aplikáciou. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"väzba na textovú službu"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania textovej služby (napr. SpellCheckerService). Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"Zaviazať k službe VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"čítanie vyrovnávacej pamäte snímok"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Umožňuje aplikácii čítať obsah vyrovnávacej pamäte snímok."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"prístup k aplikácii InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfigurovať displeje cez sieť Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Umožňuje aplikácii konfigurovať displeje a pripojiť sa k nim cez siete Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"ovládať displeje cez sieť Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikácii spravovať pravidlá siete a definovať pravidlá pre konkrétnu aplikáciu."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"zmeniť kontrolu používania siete"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikácii upraviť používanie siete jednotlivými aplikáciami. Bežné aplikácie toto nastavenie nepoužívajú."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"upravenie značiek soketov"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Umožňuje aplikácii upraviť značky soketov pre smerovanie"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"prístup k upozorneniam"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"naviazanie sa na službu na počúvanie upozornení"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň služby na počúvanie upozornení. Bežné aplikácie by toto nastavenie nemali nikdy požadovať."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolanie aplikácie pre konfiguráciu poskytnutú operátorom"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje držiteľovi vyvolať aplikáciu pre konfiguráciu poskytnutú operátorom. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Táto aplikácia nepodporuje účty pre profily s obmedzením"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Aplikácia potrebná na spracovanie tejto akcie sa nenašla"</string>
     <string name="revoke" msgid="5404479185228271586">"Odvolať"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Zrušené"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Pri zapisovaní obsahu došlo k chybe"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Zadajte kód PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Vytvoriť kód PIN pre obmedzenia upravovania"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN sa nezhodujú. Skúste to znova."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je príliš krátky. Musí mať minimálne 4 číslice."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Nespr. PIN. Skús. o 1 s"</item>
+    <item quantity="other" msgid="8030607343223287654">"Nespr. PIN. Skús. o <xliff:g id="COUNT">%d</xliff:g> s"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index fcc72bf..f303f66 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Aplikaciji omogoča premikanje opravil v ospredje in ozadje. Aplikacija lahko to naredi brez vašega nadzora."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"ustavitev programov, ki se izvajajo"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Programu omogoča odstranjevanje opravil in zapiranje njihovih programov. Zlonamerni programi lahko motijo delovanje drugih programov."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"upravljanje skladov dejavnosti"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Aplikaciji omogoča dodajanje, odstranjevanje in spreminjanje skladov dejavnosti, v katerih se izvajajo druge aplikacije. Zlonamerne aplikacije lahko motijo delovanje drugih aplikacij."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"zagon poljubne dejavnosti"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Omogoča aplikaciji zagon poljubne dejavnosti, ne glede na zaščito dovoljenj ali izvoženo stanje."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavitev združljivosti zaslona"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lastniku omogoča, da se poveže z vmesnikom načina vnosa najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"povezovanje s storitvijo za ljudi s posebnimi potrebami"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Lastniku omogoča povezovanje z vmesnikom najvišje ravni storitve za ljudi s posebnimi potrebami. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"vezava na storitev tiskanja"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Lastniku omogoča povezovanje z vmesnikom storitve tiskanja najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"dostop do vseh tiskalnih poslov"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Lastniku omogoča dostop do tiskalnih poslov, ki jih je ustvarila druga aplikacija. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"poveži z besedilno storitvijo"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Dovoljuje, da se lastnik poveže z vmesnikom besedilne storitve najvišje ravni (npr. SpellCheckerService). Tega nikoli ni treba uporabiti za navadne programe."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"povezava s storitvijo navideznega zasebnega omrežja"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Programu omogoča uporabo funkcij nizke ravni SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"branje grafičnega/slikovnega medpomnilnika"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Programu omogoča branje vsebine grafičnega/slikovnega medpomnilnika."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"dostop do funkcij InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Aplikaciji dovoljuje uporabo funkcij InputFlinger nizke ravni."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"konfiguriranje zaslonov Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Omogoča aplikaciji konfiguriranje zaslonov Wi-Fi in povezovanje z njimi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"nadzor zaslonov Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Programu omogoča upravljanje pravilnikov o omrežju in določanje pravil za program."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"spremeni obračunavanje uporabe omrežja"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Programu omogoča, da spremeni uporabo omrežja na podlagi programov. Ni za uporabo z navadnimi programi."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"spreminjanje oznak vtičnic"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Aplikaciji omogoča spreminjanje oznak vtičnic za usmerjanje"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostop do obvestil"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"poveži se s storitvijo poslušalca obvestil"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lastniku omogoča povezovanje z vmesnikom storitve poslušalca obvestil najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"priklic operaterjeve aplikacije za konfiguracijo"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lastniku omogoča sproženje operaterjeve aplikacije za konfiguracijo. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ta aplikacija ne podpira računov za profile z omejitvami"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Najdena ni bila nobena aplikacija za izvedbo tega dejanja"</string>
     <string name="revoke" msgid="5404479185228271586">"Prekliči"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Preklicano"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Napaka pri pisanju vsebine"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Vnesite PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Ustvarite PIN za spreminjanje omejitev"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kodi PIN se ne ujemata. Poskusite znova."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratek. Imeti mora vsaj 4 števke."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Napačen PIN. Poskusite znova čez eno sekundo."</item>
+    <item quantity="other" msgid="8030607343223287654">"Napačen PIN. Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> s."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 67de984..74ef9e4 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Дозвољава апликацији да премешта задатке у први план и у позадину. Апликација може да ради ово без вашег уноса."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"заустављање покренутих апликација"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозвољава апликацији да уклања задатке и уништава њихове апликације. Злонамерне апликације могу да поремете понашање других апликација."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"управљање групама активности"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Дозвољава апликацији да додаје, уклања и мења групе активности у којима се покрећу друге апликације. Злонамерне апликације могу да поремете понашање других апликација."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"покретање било које активности"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Омогућава да апликација покрене било коју активност, без обзира на заштиту дозволе или стање извоза."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"подешавање компатибилности екрана"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Омогућава да се власник обавеже на интерфејс методе уноса највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"повезивање са услугом приступачности"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дозвољава власнику да се повеже са интерфејсом услуге приступачности највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"повезивање са услугом штампања"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Дозвољава власнику да се повеже са интерфејсом услуге штампања највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"приступ свим задацима за штампање"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Дозвољава власнику да приступа задацима за штампање које је направила друга апликација. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"обавезивање на текстуалну услугу"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Омогућава власнику да се обавеже на интерфејс текстуалне услуге највишег нивоа (нпр. SpellCheckerService). Обичне апликације никада не би требало да је користе."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"везивање за VPN услугу"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дозвољава апликацији да користи SurfaceFlinger функције ниског нивоа."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"читање бафера кадрова"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дозвољава апликацији да чита садржај међумеморије кадрова."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"приступ InputFlinger функцијама"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Дозвољава апликацији да користи InputFlinger функције ниског нивоа."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"конфигурисање Wi-Fi екрана"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дозвољава апликацији да конфигурише Wi-Fi екране и повезује се са њима."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"контрола Wi-Fi екрана"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозвољава апликацији да управља смерницама за мрежу и одређује посебна правила за апликацију."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"измените обрачунавање коришћења мреже"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозвољава апликацији да измени начин на који апликације користе мрежу. Не користе је уобичајене апликације."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"измена ознака утичнице"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Дозвољава апликацији да мења ознаке утичнице за усмеравање"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"приступ обавештењима"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"позивање апликације са конфигурацијом коју одређује оператер"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозвољава власнику да позива апликацију са конфигурацијом коју одређује оператер. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ова апликација не подржава налоге за ограничене профиле"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Није пронађена ниједна апликација која би могла да обави ову радњу"</string>
     <string name="revoke" msgid="5404479185228271586">"Опозови"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Отказано је"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Грешка при исписивању садржаја"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Унесите PIN"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Направите PIN за измену ограничења"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Покушајте поново."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN је прекратак. Мора да садржи најмање 4 цифре."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Нетачан PIN. Покушајте опет за 1 сек."</item>
+    <item quantity="other" msgid="8030607343223287654">"Нетачан PIN. Покушајте опет за <xliff:g id="COUNT">%d</xliff:g> сек."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 5da8a63..cd60ac8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index a6f1ee3..0076d9af 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Inaruhusu programu kusongesha kazi hadi kwenye mandhari-mbele na mandari nyuma. Programu inaweza kufanya haya bila ya maingizo yako."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"Komesha programu zinazoendeshwa"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Huruhusu programu kuondoa majukumu na kuua programu zao. Programu hasidi zinaweza kutatiza tabia ya programu zingine."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"dhibiti bunda za shughuli"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Inaruhusu programu kuongeza, kuondoa, na kubadilisha bunda za shughuli ambamo programu nyingine huendeshwa. Programu hasidi zinaweza kusitisha tabia ya programu nyingine."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"anzisha shughuli yoyote"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Huruhusu programu kuanzisha shughuli yoyote, pasi kujali ulinzi wa idhini au hali ya nje."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"weka utangamano wa skrini"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Inaruhusu mmiliki kushurutisha kwenye kusano ya kiwango cha juu ya mbinu ya ingizo. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"funga kwa huduma ya ufikiaji"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Inamuruhusu mmiliki kufunga kipengee kinachojitokeza katika nyanja mbalimbali za kiwango cha juu cha huduma ya afikiaji. Hapaswi kuhitajika kwa programu za kawaida."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"shurutisha kwenye huduma ya kuchapisha"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Inaruhusu kishikiliaji kujifungilia kiolesura cha kiwango cha juu cha huduma ya kuchapisha. Haipaswi kuhitajika kwa programu za kawaida."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"fikia kazi zote za kuchapisha"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Huruhusu mmiliki kufikia kazi za kuchapisha zilizoundwa na programu nyingine. Haipaswi kuhitajika kwa programu za kawaida kamwe."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"Imefungwa kwa huduma ya maandishi"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Inaruhusu kishikiliaji kushurutisha kusano ya kiwango cha juu ya huduma ya matini(k.m.SpellCheckerService). Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"funga kwa huduma ya VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Inaruhusu programu kutumia vipengee vya kiwango cha chini vya SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"soma bafa ya fremu"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Inaruhusu programu kusoma maudhui ya fremu ya bafa."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"fikia InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Inaruhusu programu kutumia vipengele vya chini vya InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"sanidi maonyesho ya Wifi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Inaruhusu programu kusanidi na kuunganika kwenye maonyesho ya Wifi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"dhibiti maonyesho ya Wifi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Inaruhusu programu kudhibiti sera za mtandao na kufafanua sheria maalum za programu."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"badilisha uthibitishaji wa matumizi ya mtandao"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Huruhusu programu kurekebisha jinsi matumizi ya mtandao yana hesabika dhidi ya programu. Sio ya matumizi na programu za kawaida."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"rekebisha alama za soketi"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Inaruhusu programu kurekebisha alama za soketi za upelekaji"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"fikia arifa"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"unganisha kwenye huduma ya kisikilizi cha arifa"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Inaruhusu kishikilizi kuunganishwa kwenye kusano cha kiwango cha juu cha huduma ya kisikilizi cha arifa. Haipaswi kuhitajika tena kwa programu za kawaida."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"omba programu ya usakinishaji inayotolewa na mto huduma."</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Inaruhusu kishikiliaji kuomba programu ya usakinishaji inayotolewa na mto huduma. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Weka kanuni za nenosiri"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Dhibiti urefu na vibambo vinavyoruhusiwa katika manenosiri ya kufungua skrini."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Chunguza majaribio ya kutofun gua skrini"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangout"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,56 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Programu hii haiwezi kutumiwa na akaunti za wasifu zilizowekewa vikwazo"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Hakuna programu iliyopatikana ili kushughulikia kitendo hiki"</string>
     <string name="revoke" msgid="5404479185228271586">"Batilisha"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Barua"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Barua ya Serikali"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Kisheria"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Mwanasheria Mdogo"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Leja"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Gazeti"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Imeghairiwa"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Hitilafu katika kuandika maudhui"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Ingiza PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN ya sasa"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"PIN mpya"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Thibitisha PIN mpya"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Unda PIN ya kurekebisha vikwazo"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN hazilingani. Jaribu tena."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ni fupi mno. Lazima iwe angalau tarakimu 4."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"PIN sio sahihi. Jaribu tena baada ya sekunde 1."</item>
+    <item quantity="other" msgid="8030607343223287654">"PIN sio sahihi. Jaribu tena baada ya sekunde <xliff:g id="COUNT">%d</xliff:g>."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index f1d4c3c..786d441 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 2d9ed63..0770504 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 87c3c48..4e3cef6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Uygulamaya, görevleri ön plana ve arka plana taşıma izni verir. Uygulama bunu sizden bir giriş olmadan yapabilir."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"çalışan uygulamaları durdur"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Uygulamaya, görevleri kaldırma ve bunlara ait uygulamaları kapatma izni verir. Kötü amaçlı uygulamalar diğer uygulamaların çalışmasını bozabilir."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"etkinlik yığınlarını yönet"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Uygulamaya, diğer uygulamaların içinde çalıştığı etkinlik yığınlarını ekleme, kaldırma ve değiştirme izni verir. Kötü amaçlı uygulamalar diğer uygulamaların davranışlarını olumsuz etkileyebilir."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"herhangi bir etkinlik başlat"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Uygulamaya, izin koruma veya dışa aktarma durumu ne olursa olsun bir etkinlik başlatma izni verir."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ekran uyumluluğunu ayarla"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Cihazın sahibine, bir giriş yönteminin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"erişilebilirlik hizmetine bağlan"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"İzin sahibine bir erişilebilirlik hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"bir yazdırma hizmetine bağlan"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"İzin sahibine, bir yazdırma hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"tüm yazdırma işlerine eriş"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"İzin sahibine, başka uygulama tarafından oluşturulan yazdırma işlerine erişim izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"kısa mesaj hizmetine bağla"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Cihazın sahibine, bir metin hizmetinin (ör. SpellCheckerService) en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerekmez."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"VPN hizmetine bağlan"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Uygulamaya, SurfaceFlinger\'a ait düşük düzey özellikleri kullanma izni verir."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"çerçeve arabelleğini oku"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Uygulamaya, çerçeve arabelleğinin içeriğini okuma izni verir."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"InputFlinger\'a eriş"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Uygulamaya, alt düzey InputFlinger özelliklerini kullanma izni verir."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"Kablosuz ekranları yapılandır"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Uygulamaya kablosuz ekranları yapılandırma ve bunlara bağlanma izni verir."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"Kablosuz ekranları denetle"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Uygulamaya, ağ politikalarını yönetme ve uygulamaya özgü kuralları tanımlama izni verir."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ağ kullanım hesaplamasını değiştir"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Uygulamaya, ağın uygulamalara göre nasıl kullanılacağını değiştirme izni verir. Normal uygulamalar tarafından kullanılmak için değildir."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"soket işaretlerini değiştir"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Uygulamaya, yönlendirme için soket işaretlerini değiştirme izni verir"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"bildirimlere eriş"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirim dinleyici hizmetine bağlan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"İzin sahibine bir bildirim dinleyici hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"operatör tarafından sağlanan yapılandırma uygulamasını çalıştır"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"İzin sahibine, operatör tarafından sağlanan yapılandırma uygulamasını çalıştırma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Bu uygulama, kısıtlanmış profillerin hesaplarını desteklemez"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Bu eylemi gerçekleştirecek bir uygulama bulunamadı"</string>
     <string name="revoke" msgid="5404479185228271586">"İptal et"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"İptal edildi"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"İçerik yazılırken hata oluştu"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"PIN\'i girin"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Kısıtlamaları değiştirmek için PIN oluşturun"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN\'ler eşleşmiyor. Tekrar deneyin."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN çok kısa. En az 4 basamaklı olmalı."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Yanlış PIN. 1 saniye içinde tekrar deneyin."</item>
+    <item quantity="other" msgid="8030607343223287654">"Yanlış PIN. <xliff:g id="COUNT">%d</xliff:g> saniye içinde tekrar deneyin."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 099fb91..47ad171 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Дозволяє програмі переміщувати завдання в активні чи фонові вікна. Програма може робити це без вашого відома."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"зупиняти запущені програми"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозволяє програмі видаляти завдання та примусово припиняти роботу відповідних програм. Шкідливі програми можуть переривати роботу інших програм."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"керувати стеками дій"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Дозволяє програмі додавати, вилучати та змінювати стеки дій, у яких запущено інші програми. Шкідливі програми можуть переривати роботу інших програм."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"розпочинати будь-які дії"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Дозволяє програмі розпочинати будь-які дії, незалежно від захищеного дозволу або стану експорту."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"установити сумісність екрана"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня методу введення. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"прив’язуватися до служби доступності"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби доступності. Ніколи не застосовується для звичайних програм."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"прив’язуватися до служби друку"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби друку. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"отримувати доступ до всіх завдань друку"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Дозволяє власнику отримувати доступ до завдань друку, створених в іншій програмі. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"прив’язати до текстової служби"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня текстової служби (напр. SpellCheckerService). Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"прив’язуватися до служби VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дозволяє програмі використовувати низькорівневі функції SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"читати фрейм-буфер"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дозволяє програмі читати вміст буфера кадрів."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"отримувати доступ до InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Дозволяє програмі використовувати низькорівневі функції InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"налаштувати екрани Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Дозволяє програмі налаштовувати екрани Wi-Fi і під’єднуватися до них."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"керувати екранами Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозволяє програмі керувати політикою мережі та визначити спеціальні правила для програм."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змінювати облік використання мережі"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозволяє програмі змінювати метод підрахунку того, як програми використовують мережу. Не для використання звичайними програмами."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"змінювати мітки сокетів"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Дозволяє програмі змінювати мітки сокетів для маршрутизації"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"отримувати доступ до сповіщень"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"викликати надану оператором програму конфігурації"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозволяє власнику викликати надану оператором програму конфігурації. Ніколи не застосовується для звичайних програм."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1527,98 +1514,59 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Ця програма не підтримує облікові записи для обмежених профілів"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Не знайдено програму для обробки цієї дії"</string>
     <string name="revoke" msgid="5404479185228271586">"Анулювати"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Скасовано"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Помилка записування вмісту"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Введіть PIN-код"</string>
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
     <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Створіть PIN-код для змінення обмежень"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-коди не збігаються. Повторіть спробу."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код закороткий. Має бути принаймні 4 цифри."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"Неправильний PIN. Повторіть через 1 с"</item>
+    <item quantity="other" msgid="8030607343223287654">"Неправильний PIN. Повторіть через <xliff:g id="COUNT">%d</xliff:g> с"</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 6f339e6..31760d1 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d39cd3f..fbf8c9a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index a9f7b7b..045314a 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1609,11 +1609,15 @@
     <skip />
     <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
     <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
     <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
     <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
     <skip />
     <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
     <skip />
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 2957366..7152ebf 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -279,10 +279,8 @@
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Ivumela uhlelo lokusebenza ukugudluza imisebenzi ngaphambili nangasemuva. Uhlelo lokusebenza lungenza lokhu ngaphandle kwakho."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinsiza ezisebenzayo"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi insiza isuse okumele kwenziwe ibulale nezinsiza zakho. Izinsiza eziwubungozi zingaphazamisa ukusebenza kwezinye izinsiza."</string>
-    <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
-    <skip />
-    <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
-    <skip />
+    <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"phatha izitaki zomsebenzi"</string>
+    <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Ivumela uhlelo lokusebenza ukuthi lingeze, lisuse, noma lilungise izitaki zomsebenzi lapho ezinye izinhlelo zokusebenza ziqalisa khona. Izinhlelo zokusebenza ezinobungozi zingaphazamisa ukuziphatha kwezinye izinhlelo zokusebenza."</string>
     <string name="permlab_startAnyActivity" msgid="2918768238045206456">"qala noma imuphi umsebenzi"</string>
     <string name="permdesc_startAnyActivity" msgid="997823695343584001">"Ivumela uhlelo lokusebenza ukuqala umsebenzi, ngaphandle kokuvukeleka kwemvume noma isimo sokukhishiwe."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setha ukuhambelana kwesikrini"</string>
@@ -360,14 +358,10 @@
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Ivumela isimeli ukuhlanganisa uxhumano nomsebenzisi wezinga eliphezulu lendlela yokufaka. Ayisoze yadingeka kwizinhlelo ezivamile."</string>
     <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"hlanganisa kusevisi yokufinyeleleka"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Ivumela isibambi ukuhlanganisa uxhumo nomsebenzisi kwezinga eliphezulu lesevisi yesinqunjwana. Akusoze kwadingekela izinhlelo zokusebenza ezivamile."</string>
-    <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
-    <skip />
-    <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
-    <skip />
-    <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
-    <skip />
-    <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
-    <skip />
+    <string name="permlab_bindPrintService" msgid="8462815179572748761">"bophezela kusevisi yokuphrinta"</string>
+    <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Ivumela umnikazi ukuthi abophezele isixhumanisi esibonakalayo sezinga eliphezulu sesevisi lokuphrinta. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
+    <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"finyelela kuyo yonke imisebenzi yokuphrinta"</string>
+    <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Ivumela umnikazi ukuthi afinyelele imisebenzi yokushicilela edalwe olunye uhlelo lokusebenza. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"bophezela kunsizakalo yombhalo"</string>
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwesixhumi esibonakalayo sensizakalo yombhalo(isb. InsizakaloYokuhlolaUkubhala). Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"hlanganisa kwinsizakalo ye-VPN"</string>
@@ -470,10 +464,8 @@
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Ivumela insiza ukuthi isebenzise okuqukethwe i-SurfaceFlinger okusezingeni eliphansi."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"funda isikhumbuli sesikhashana sendikimba"</string>
     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Ivumela insiza ukuthi ifunde okuqukethwe ifreyimu yebhafa."</string>
-    <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
-    <skip />
-    <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
-    <skip />
+    <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"finyelela ku-InputFlinger"</string>
+    <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Ivumela uhlelo lokusebenza ukuthi lusebenzise izici zezinga eliphansi ze-InputFlinger."</string>
     <string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"lungisa ukubukwa kwe-Wi-Fi"</string>
     <string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Ivumela uhlelo lokusebenza ukulungisa nokuxhuma ekubukisweni kwe-Wi-Fi."</string>
     <string name="permlab_controlWifiDisplay" msgid="393641276723695496">"lawula ukubukwa kwe-Wi-Fi"</string>
@@ -643,18 +635,14 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela insiza ukuthi yengamele iigomo iphinde ichaze imithetho ehambisana ngqo nensiza."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"lungisa ukubala kokusebenza kohleloxhumano"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela insiza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinsiza ezijwayelekile."</string>
-    <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
-    <skip />
-    <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
-    <skip />
+    <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"shintsha izimpawu zesokhethi"</string>
+    <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Ivumela uhlelo lokusebenza ukuthi lilungise izimpawu zesokhethi zomzila"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"finyelela kuzaziso"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bophezela kwisevisi yomlaleli wesaziso"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ivumela umbambi ukubophezela kwisixhumi esibonakalayo sezinga eliphezulu lesevisi yomlaleli wesaziso. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
-    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
-    <skip />
-    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
-    <skip />
+    <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"buyisela uhlelo lokusebenza lokulungiselelwa okunikezwe yinkampani yenethiwekhi"</string>
+    <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ivumela umnikazi ukuthi abuyisele uhlelo lokusebenza lokulungiselelwa. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
@@ -764,8 +752,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"i-Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"i-Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
-    <skip />
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Ama-Hangout"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"i-ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"i-Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"Umhlangano we-Net"</string>
@@ -1527,98 +1514,56 @@
     <string name="app_no_restricted_accounts" msgid="5739463249673727736">"Lolu hlelo lokusebenza alusekeli ama-akhawunti wamaphrofayela akhawulelwe"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Alukho uhlelo lokusebenza olutholakele lokuphatha lesi senzo"</string>
     <string name="revoke" msgid="5404479185228271586">"Chitha"</string>
-    <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
-    <skip />
-    <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
-    <skip />
-    <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
-    <skip />
-    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
-    <skip />
-    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
-    <skip />
-    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
-    <skip />
-    <!-- no translation found for restr_pin_confirm_pin (2891475237150965991) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
-    <skip />
-    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
-    <skip />
-    <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
-    <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+    <string name="mediaSize_iso_a0" msgid="7875427489420821793">"I-ISO A0"</string>
+    <string name="mediaSize_iso_a1" msgid="3760734499050875356">"I-ISO A1"</string>
+    <string name="mediaSize_iso_a2" msgid="5973266378020144382">"I-ISO A2"</string>
+    <string name="mediaSize_iso_a3" msgid="1373407105687300884">"I-ISO A3"</string>
+    <string name="mediaSize_iso_a4" msgid="6689772807982597254">"I-ISO A4"</string>
+    <string name="mediaSize_iso_a5" msgid="5353549652015741040">"I-ISO A5"</string>
+    <string name="mediaSize_iso_a6" msgid="8585038048674911907">"I-ISO A6"</string>
+    <string name="mediaSize_iso_a7" msgid="6641836716963839119">"I-ISO A7"</string>
+    <string name="mediaSize_iso_a8" msgid="7571139437465693355">"I-ISO A8"</string>
+    <string name="mediaSize_iso_a9" msgid="1378455891957115079">"I-ISO A9"</string>
+    <string name="mediaSize_iso_a10" msgid="2480747457429475344">"I-ISO A10"</string>
+    <string name="mediaSize_iso_b0" msgid="3965935097661108039">"I-ISO B0"</string>
+    <string name="mediaSize_iso_b1" msgid="2505753285010115437">"I-ISO B1"</string>
+    <string name="mediaSize_iso_b2" msgid="8763874709859458453">"I-ISO B2"</string>
+    <string name="mediaSize_iso_b3" msgid="4210506688191764076">"I-ISO B3"</string>
+    <string name="mediaSize_iso_b4" msgid="5749404165888526034">"I-ISO B4"</string>
+    <string name="mediaSize_iso_b5" msgid="7640627414621904733">"I-ISO B5"</string>
+    <string name="mediaSize_iso_b6" msgid="7342988864712748544">"I-ISO B6"</string>
+    <string name="mediaSize_iso_b7" msgid="5069844065235382429">"I-ISO B7"</string>
+    <string name="mediaSize_iso_b8" msgid="7316818922278779774">"I-ISO B8"</string>
+    <string name="mediaSize_iso_b9" msgid="5414727094026532341">"I-ISO B9"</string>
+    <string name="mediaSize_iso_b10" msgid="5251253731832048185">"I-ISO B10"</string>
+    <string name="mediaSize_iso_c0" msgid="4003138342671964217">"I-ISO C0"</string>
+    <string name="mediaSize_iso_c1" msgid="1935188063393553008">"I-ISO C1"</string>
+    <string name="mediaSize_iso_c2" msgid="3197307969712069904">"I-ISO C2"</string>
+    <string name="mediaSize_iso_c3" msgid="4335826087321913508">"I-ISO C3"</string>
+    <string name="mediaSize_iso_c4" msgid="3745639598281015005">"I-ISO C4"</string>
+    <string name="mediaSize_iso_c5" msgid="8269457765822791013">"I-ISO C5"</string>
+    <string name="mediaSize_iso_c6" msgid="566666105260346930">"I-ISO C6"</string>
+    <string name="mediaSize_iso_c7" msgid="8678413180782608498">"I-ISO C7"</string>
+    <string name="mediaSize_iso_c8" msgid="8392376206627041730">"I-ISO C8"</string>
+    <string name="mediaSize_iso_c9" msgid="9191613372324845405">"I-ISO C9"</string>
+    <string name="mediaSize_iso_c10" msgid="7327709699184920822">"I-ISO C10"</string>
+    <string name="mediaSize_na_letter" msgid="4191805615829472953">"Incwadi"</string>
+    <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Incwadi kahulumeni"</string>
+    <string name="mediaSize_na_legal" msgid="6697982988283823150">"Okusemthethweni"</string>
+    <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Ezomthetho ezincane"</string>
+    <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ileja"</string>
+    <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Iphephandaba"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Kukhanseliwe"</string>
+    <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Iphutha ekubhaleni okuqukethwe"</string>
+    <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Faka i-PIN"</string>
+    <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"I-PIN yamanje"</string>
+    <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"I-PIN entsha"</string>
+    <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Qinisekisa i-PIN entsha"</string>
+    <string name="restr_pin_create_pin" msgid="8017600000263450337">"Dala i-PIN yemikhawulo yokushintsha"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Ama-PIN awafani. Zama futhi."</string>
+    <string name="restr_pin_error_too_short" msgid="8173982756265777792">"I-PIN yimfushane kakhulu. Okungenani kumele ibe namadijithi angu-4."</string>
+  <plurals name="restr_pin_countdown">
+    <item quantity="one" msgid="4835639969503729874">"I-PIN engalungile. Zama futhi ngesekhondi elingu-1."</item>
+    <item quantity="other" msgid="8030607343223287654">"I-PIN engalungile. Zama futhi kumasekhondi angu-<xliff:g id="COUNT">%d</xliff:g>."</item>
+  </plurals>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 194da10..6a8381f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2578,6 +2578,31 @@
         <attr name="vendor" format="string"/>
     </declare-styleable>
 
+    <!-- Use <code>apdu-service</code> as the root tag of the XML resource that
+         describes an {@link android.nfc.cardemulation.HostApduService} or
+         {@link android.nfc.cardemulation.SeApduService} service, which is referenced
+         from its SERVICE_META_DATA entry. -->
+    <declare-styleable name="ApduService">
+        <!-- Set to true to let the NFC subsystem know that this service implements
+             a payment instrument. That will allow this service to be enumerated in
+             a list of payment services, where the user can pick his preferred payment
+             service. The preferred service will be bound to persistently, to make sure
+             it can immediately process APDUs without service startup delay. This is vital
+             for existing payment infrastructure that has very strict timing requirements. -->
+        <attr name="paymentService" format="boolean" />
+        <!-- Short description of the functionality the serivce implements.-->
+        <attr name="description" />
+    </declare-styleable>
+
+    <!-- Specify one or more <code>aid-filter</code> elements inside a <code>apdu-service</code>
+         element to list the ISO7816 Application ID (AIDs) your service can handle.-->
+    <declare-styleable name="AidFilter">
+        <!-- The ISO7816 Application ID -->
+        <attr name="name" />
+        <!-- Short description of what the AID implements.-->
+        <attr name="description" />
+    </declare-styleable>
+
     <declare-styleable name="ActionMenuItemView">
         <attr name="minWidth" />
     </declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index da6dfd3..1a5dc37 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1153,4 +1153,8 @@
         <item>com.android.inputmethod.latin</item>
     </string-array>
 
+    <string-array name="config_notificationScorers">
+        <item>com.android.internal.notification.DemoContactNotificationScorer</item>
+    </string-array>
+
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3ab8825..7de2705 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2068,5 +2068,5 @@
   <public type="attr" name="sspPattern" />
   <public type="attr" name="addPrintersActivity" />
   <public type="attr" name="vendor" />
-
+  <public type="attr" name="paymentService" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index eba3f42..8743119 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1021,6 +1021,12 @@
         a device administrator. 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_manageDeviceAdmins">add or remove a device admin</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_manageDeviceAdmins">Allows the holder to add or remove active device
+        administrators. 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_setOrientation">change screen orientation</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_setOrientation">Allows the app to change
@@ -4256,12 +4262,16 @@
     <!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] -->
     <string name="write_fail_reason_cannot_write">Error writing content</string>
 
+    <!-- PIN entry dialog label/hint for PIN [CHAR LIMIT=none] -->
+    <string name="restr_pin_enter_pin">Enter PIN</string>
+    <!-- PIN entry dialog label/hint for old PIN [CHAR LIMIT=none] -->
+    <string name="restr_pin_enter_old_pin">Current PIN</string>
+    <!-- PIN entry dialog label for new PIN [CHAR LIMIT=none] -->
+    <string name="restr_pin_enter_new_pin">New PIN</string>
+    <!-- PIN entry dialog label for new PIN confirmation [CHAR LIMIT=none] -->
+    <string name="restr_pin_confirm_pin">Confirm new PIN</string>
     <!-- PIN creation dialog message [CHAR LIMIT=none] -->
     <string name="restr_pin_create_pin">Create a PIN for modifying restrictions</string>
-    <!-- PIN entry dialog label for PIN [CHAR LIMIT=none] -->
-    <string name="restr_pin_enter_pin">Enter PIN</string>
-    <!-- PIN entry dialog label for PIN confirmation [CHAR LIMIT=none] -->
-    <string name="restr_pin_confirm_pin">Confirm PIN</string>
     <!-- PIN entry dialog error when PINs are not the same [CHAR LIMIT=none] -->
     <string name="restr_pin_error_doesnt_match">PINs don\'t match. Try again.</string>
     <!-- PIN entry dialog error when PIN is too short [CHAR LIMIT=none] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e29e82b..f1f826d 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -214,8 +214,9 @@
   <java-symbol type="id" name="breadcrumb_section" />
   <java-symbol type="id" name="action_bar_spinner" />
   <java-symbol type="id" name="pin_message" />
-  <java-symbol type="id" name="pin1_text" />
-  <java-symbol type="id" name="pin2_text" />
+  <java-symbol type="id" name="pin_text" />
+  <java-symbol type="id" name="pin_new_text" />
+  <java-symbol type="id" name="pin_confirm_text" />
   <java-symbol type="id" name="pin_error_message" />
 
   <java-symbol type="attr" name="actionModeShareDrawable" />
@@ -1157,7 +1158,8 @@
   <java-symbol type="layout" name="sms_short_code_confirmation_dialog" />
   <java-symbol type="layout" name="action_bar_up_container" />
   <java-symbol type="layout" name="app_not_authorized" />
-  <java-symbol type="layout" name="pin_challenge" />
+  <java-symbol type="layout" name="restrictions_pin_challenge" />
+  <java-symbol type="layout" name="restrictions_pin_setup" />
 
   <java-symbol type="anim" name="slide_in_child_bottom" />
   <java-symbol type="anim" name="slide_in_right" />
@@ -1568,6 +1570,7 @@
   <java-symbol type="id" name="button_once" />
   <java-symbol type="id" name="button_always" />
   <java-symbol type="integer" name="config_maxResolverActivityColumns" />
+  <java-symbol type="array" name="config_notificationScorers" />
 
   <!-- From SystemUI -->
   <java-symbol type="anim" name="push_down_in" />
diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk
index e16a92d..2897b04 100644
--- a/data/sounds/AudioPackage11.mk
+++ b/data/sounds/AudioPackage11.mk
@@ -43,7 +43,7 @@
 	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Tejat_proc48.ogg:system/media/audio/notifications/Tejat.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
 	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
 	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
diff --git a/data/sounds/notifications/ogg/Tejat_proc48.ogg b/data/sounds/notifications/ogg/Tejat_proc48.ogg
new file mode 100644
index 0000000..b1637d7
--- /dev/null
+++ b/data/sounds/notifications/ogg/Tejat_proc48.ogg
Binary files differ
diff --git a/data/sounds/notifications/wav/Deneb_processed_48kHz.wav b/data/sounds/notifications/wav/Deneb_processed_48kHz.wav
new file mode 100644
index 0000000..e2df8e9
--- /dev/null
+++ b/data/sounds/notifications/wav/Deneb_processed_48kHz.wav
Binary files differ
diff --git a/docs/html/about/versions/android-4.3.jd b/docs/html/about/versions/android-4.3.jd
index 0ca3bc6..d0ccfbe 100644
--- a/docs/html/about/versions/android-4.3.jd
+++ b/docs/html/about/versions/android-4.3.jd
@@ -7,7 +7,7 @@
 
 <div id="qv-wrapper">
 <div id="qv">
-  
+
 <h2>In this document
     <a href="#" onclick="hideNestedItems('#toc43',this);return false;" class="header-toggle">
         <span class="more">show more</span>
@@ -62,7 +62,6 @@
   </li>
   <li><a href="#UserInput">User Input</a>
     <ol>
-      <li><a href="#SignificantMotion">Detect significant motion</a></li>
       <li><a href="#Sensors">New sensor types</a></li>
     </ol>
   </li>
@@ -133,7 +132,7 @@
 Then build your apps against the Android {@sdkPlatformVersion} platform to begin using the
 latest APIs.</p>
 
-  
+
 <h3 id="ApiLevel">Update your target API level</h3>
 
 <p>To better optimize your app for devices running Android {@sdkPlatformVersion},
@@ -145,7 +144,7 @@
 <p>You can use APIs in Android {@sdkPlatformVersion} while also supporting older versions by adding
 conditions to your code that check for the system API level before executing
 APIs not supported by your <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>. 
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>.
 To learn more about maintaining backward compatibility, read <a
 href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different
 Platform Versions</a>.</p>
@@ -172,11 +171,11 @@
 
 <p>Your app might misbehave in a restricted profile environment.</p>
 
-<p>Users in a <a href="#RestrictedProfiles">restricted profile</a> environment might not 
-have all the standard Android apps available. For example, a restricted profile might have the 
-web browser and camera app disabled. So your app should not make assumptions about which apps are 
-available, because if you call {@link android.app.Activity#startActivity startActivity()} without 
-verifying whether an app is available to handle the {@link android.content.Intent}, 
+<p>Users in a <a href="#RestrictedProfiles">restricted profile</a> environment might not
+have all the standard Android apps available. For example, a restricted profile might have the
+web browser and camera app disabled. So your app should not make assumptions about which apps are
+available, because if you call {@link android.app.Activity#startActivity startActivity()} without
+verifying whether an app is available to handle the {@link android.content.Intent},
 your app might crash in a restricted profile.</p>
 
 <p>When using an implicit intent, you should always verify that an app is available to handle the intent by calling {@link android.content.Intent#resolveActivity resolveActivity()} or {@link android.content.pm.PackageManager#queryIntentActivities queryIntentActivities()}. For example:</p>
@@ -197,20 +196,20 @@
 <p>Your app might misbehave in a restricted profile environment.</p>
 
 <p>Users within a restricted profile environment do not have access to user accounts by default.
-If your app depends on an {@link android.accounts.Account}, then your app might crash or behave 
+If your app depends on an {@link android.accounts.Account}, then your app might crash or behave
 unexpectedly when used in a restricted profile.</p>
 
 <p>If you'd like to prevent restricted profiles from using your app entirely because your
-app depends on account information that's sensitive, specify the <a 
-href="{@docRoot}guide/topics/manifest/application-element.html#requiredAccountType">{@code 
-android:requiredAccountType}</a> attribute in your manifest's <a 
-href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application>}</a> 
+app depends on account information that's sensitive, specify the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#requiredAccountType">{@code
+android:requiredAccountType}</a> attribute in your manifest's <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application>}</a>
 element.</p>
 
-<p>If you’d like to allow restricted profiles to continue using your app even though they can’t 
-create their own accounts, then you can either disable your app features that require an account 
+<p>If you’d like to allow restricted profiles to continue using your app even though they can’t
+create their own accounts, then you can either disable your app features that require an account
 or allow restricted profiles to access the accounts created by the primary user. For more
-information, see the section 
+information, see the section
 below about <a href="#AccountsInProfile">Supporting accounts in a restricted profile</a>.</p>
 
 
@@ -218,67 +217,67 @@
 
 <h2 id="RestrictedProfiles">Restricted Profiles</h2>
 
-<p>On Android tablets, users can now create restricted profiles based on the primary user. 
+<p>On Android tablets, users can now create restricted profiles based on the primary user.
 When users create a restricted profile, they can enable restrictions such as which apps are
 available to the profile. A new set of APIs in Android 4.3 also allow you to build fine-grain
-restriction settings for the apps you develop. For example, by using the new APIs, you can 
-allow users to control what type of content is available within your app when running in a 
+restriction settings for the apps you develop. For example, by using the new APIs, you can
+allow users to control what type of content is available within your app when running in a
 restricted profile environment.</p>
 
-<p>The UI for users to control the restrictions you've built is managed by the system's 
+<p>The UI for users to control the restrictions you've built is managed by the system's
 Settings application. To make your app's restriction settings appear to the user,
-you must declare the restrictions your app provides by creating a {@link 
-android.content.BroadcastReceiver} that receives the {@link android.content.Intent#ACTION_GET_RESTRICTION_ENTRIES} intent. The system invokes this intent to query 
-all apps for available restrictions, then builds the UI to allow the primary user to 
+you must declare the restrictions your app provides by creating a {@link
+android.content.BroadcastReceiver} that receives the {@link android.content.Intent#ACTION_GET_RESTRICTION_ENTRIES} intent. The system invokes this intent to query
+all apps for available restrictions, then builds the UI to allow the primary user to
 manage restrictions for each restricted profile. </p>
 
-<p>In the {@link android.content.BroadcastReceiver#onReceive onReceive()} method of 
-your {@link android.content.BroadcastReceiver}, you must create a {@link 
-android.content.RestrictionEntry} for each restriction your app provides. Each {@link 
-android.content.RestrictionEntry} defines a restriction title, description, and one of the 
+<p>In the {@link android.content.BroadcastReceiver#onReceive onReceive()} method of
+your {@link android.content.BroadcastReceiver}, you must create a {@link
+android.content.RestrictionEntry} for each restriction your app provides. Each {@link
+android.content.RestrictionEntry} defines a restriction title, description, and one of the
 following data types:</p>
 
 <ul>
-  <li>{@link android.content.RestrictionEntry#TYPE_BOOLEAN} for a restriction that is 
+  <li>{@link android.content.RestrictionEntry#TYPE_BOOLEAN} for a restriction that is
   either true or false.
-  <li>{@link android.content.RestrictionEntry#TYPE_CHOICE} for a restriction that has 
+  <li>{@link android.content.RestrictionEntry#TYPE_CHOICE} for a restriction that has
   multiple choices that are mutually exclusive (radio button choices).
-  <li>{@link android.content.RestrictionEntry#TYPE_MULTI_SELECT} for a restriction that 
+  <li>{@link android.content.RestrictionEntry#TYPE_MULTI_SELECT} for a restriction that
   has multiple choices that are <em>not</em> mutually exclusive (checkbox choices).
 </ul>
 
-<p>You then put all the {@link android.content.RestrictionEntry} objects into an {@link 
-java.util.ArrayList} and put it into the broadcast receiver's result as the value for the 
+<p>You then put all the {@link android.content.RestrictionEntry} objects into an {@link
+java.util.ArrayList} and put it into the broadcast receiver's result as the value for the
 {@link android.content.Intent#EXTRA_RESTRICTIONS_LIST} extra.</p>
 
-<p>The system creates the UI for your app's restrictions in the Settings app and saves each 
-restriction with the unique key you provided for each {@link android.content.RestrictionEntry} 
-object. When the user opens your app, you can query for any current restrictions by 
-calling {@link android.os.UserManager#getApplicationRestrictions getApplicationRestrictions()}. 
+<p>The system creates the UI for your app's restrictions in the Settings app and saves each
+restriction with the unique key you provided for each {@link android.content.RestrictionEntry}
+object. When the user opens your app, you can query for any current restrictions by
+calling {@link android.os.UserManager#getApplicationRestrictions getApplicationRestrictions()}.
 This returns a {@link android.os.Bundle} containing the key-value pairs for each restriction
 you defined with the {@link android.content.RestrictionEntry} objects.</p>
 
-<p>If you want to provide more specific restrictions that can't be handled by boolean, single 
-choice, and multi-choice values, then you can create an activity where the user can specify the 
-restrictions and allow users to open that activity from the restriction settings. In your 
-broadcast receiver, include the {@link android.content.Intent#EXTRA_RESTRICTIONS_INTENT} extra 
+<p>If you want to provide more specific restrictions that can't be handled by boolean, single
+choice, and multi-choice values, then you can create an activity where the user can specify the
+restrictions and allow users to open that activity from the restriction settings. In your
+broadcast receiver, include the {@link android.content.Intent#EXTRA_RESTRICTIONS_INTENT} extra
 in the result {@link android.os.Bundle}. This extra must specify an {@link android.content.Intent}
-indicating the {@link android.app.Activity} class to launch (use the 
-{@link android.os.Bundle#putParcelable putParcelable()} method to pass {@link 
+indicating the {@link android.app.Activity} class to launch (use the
+{@link android.os.Bundle#putParcelable putParcelable()} method to pass {@link
 android.content.Intent#EXTRA_RESTRICTIONS_INTENT} with the intent).
-When the primary user enters your activity to set custom restrictions, your 
-activity must then return a result containing the restriction values in an extra using either 
-the {@link android.content.Intent#EXTRA_RESTRICTIONS_LIST} or {@link 
+When the primary user enters your activity to set custom restrictions, your
+activity must then return a result containing the restriction values in an extra using either
+the {@link android.content.Intent#EXTRA_RESTRICTIONS_LIST} or {@link
 android.content.Intent#EXTRA_RESTRICTIONS_BUNDLE} key, depending on whether you specify
 {@link android.content.RestrictionEntry} objects or key-value pairs, respectively.</p>
 
 
 <h3 id="AccountsInProfile">Supporting accounts in a restricted profile</h3>
 
-<p>Any accounts added to the primary user are available to a restricted profile, but the 
-accounts are not accessible from the {@link android.accounts.AccountManager} APIs by default. 
+<p>Any accounts added to the primary user are available to a restricted profile, but the
+accounts are not accessible from the {@link android.accounts.AccountManager} APIs by default.
 If you attempt to add an account with {@link android.accounts.AccountManager} while in a restricted
-profile, you will get a failure result. Due to these restrictions, you have the following 
+profile, you will get a failure result. Due to these restrictions, you have the following
 three options:</p>
 
 <li><strong>Allow access to the owner’s accounts from a restricted profile.</strong>
@@ -289,21 +288,25 @@
     android:restrictedAccountType="com.example.account.type" >
 </pre>
 
-<p class="caution"><strong>Caution:</strong> Enabling this attribute provides your 
-app access to the primary user's accounts from restricted profiles. So you should allow this 
+<p class="caution"><strong>Caution:</strong> Enabling this attribute provides your
+app access to the primary user's accounts from restricted profiles. So you should allow this
 only if the information displayed by your app does not reveal personally identifiable
-information (PII) that’s considered sensitive.</p>
+information (PII) that’s considered sensitive. The system settings will inform the primary
+user that your app grants restricted profiles to their accounts, so it should be clear to the user
+that account access is important for your app's functionality. If possible, you should also
+provide adequate restriction controls for the primary user that define how much account access
+is allowed in your app.</p>
 </li>
 
 
 <li><strong>Disable certain functionality when unable to modify accounts.</strong>
-<p>If you want to use accounts, but don’t actually require them for your app’s primary 
-functionality, you can check for account availability and disable features when not available. 
-You should first check if there is an existing account available. If not, then query whether 
-it’s possible to create a new account by calling {@link 
-android.os.UserManager#getUserRestrictions()} and check the {@link 
-android.os.UserManager#DISALLOW_MODIFY_ACCOUNTS} extra in the result. If it is {@code true}, 
-then you should disable whatever functionality of your app requires access to accounts. 
+<p>If you want to use accounts, but don’t actually require them for your app’s primary
+functionality, you can check for account availability and disable features when not available.
+You should first check if there is an existing account available. If not, then query whether
+it’s possible to create a new account by calling {@link
+android.os.UserManager#getUserRestrictions()} and check the {@link
+android.os.UserManager#DISALLOW_MODIFY_ACCOUNTS} extra in the result. If it is {@code true},
+then you should disable whatever functionality of your app requires access to accounts.
 For example:</p>
 <pre>
 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -312,15 +315,15 @@
    // cannot add accounts, disable some functionality
 }
 </pre>
-<p class="note"><strong>Note:</strong> In this scenario, you should <em>not</em> declare 
+<p class="note"><strong>Note:</strong> In this scenario, you should <em>not</em> declare
 any new attributes in your manifest file.</p>
 </li>
 
 <li><strong>Disable your app when unable to access private accounts.</strong>
-<p>If it’s instead important that your app not be available to restricted profiles because 
-your app depends on sensitive personal information in an account (and because restricted profiles 
+<p>If it’s instead important that your app not be available to restricted profiles because
+your app depends on sensitive personal information in an account (and because restricted profiles
 currently cannot add new accounts), add
-the <a href="{@docRoot}guide/topics/manifest/application-element.html#requiredAccountType">{@code 
+the <a href="{@docRoot}guide/topics/manifest/application-element.html#requiredAccountType">{@code
 android:requiredAccountType}</a> attribute to the <a
 href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application></a> tag:</p>
 <pre>
@@ -338,11 +341,11 @@
 
 <h3 id="BTLE">Bluetooth Low Energy (Smart Ready)</h3>
 
-<p>Android now supports Bluetooth Low Energy (LE) with new APIs in {@link android.bluetooth}. 
-With the new APIs, you can build Android apps that communicate with Bluetooth Low Energy 
+<p>Android now supports Bluetooth Low Energy (LE) with new APIs in {@link android.bluetooth}.
+With the new APIs, you can build Android apps that communicate with Bluetooth Low Energy
 peripherals such as heart rate monitors and pedometers.</p>
 
-<p>Because Bluetooth LE is a hardware feature that is not available on all 
+<p>Because Bluetooth LE is a hardware feature that is not available on all
 Android-powered devices, you must declare in your manifest file a <a
 href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature>}</a>
 element for {@code "android.hardware.bluetooth_le"}:</p>
@@ -350,11 +353,11 @@
 &lt;uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
 </pre>
 
-<p>If you're already familiar with Android's Classic Bluetooth APIs, notice that using the 
-Bluetooth LE APIs has some differences. Most importantly is that there's now a {@link 
-android.bluetooth.BluetoothManager} class that you should use for some high level operations 
-such as acquiring a {@link android.bluetooth.BluetoothAdapter}, getting a list of connected 
-devices, and checking the state of a device. For example, here's how you should now get the 
+<p>If you're already familiar with Android's Classic Bluetooth APIs, notice that using the
+Bluetooth LE APIs has some differences. Most importantly is that there's now a {@link
+android.bluetooth.BluetoothManager} class that you should use for some high level operations
+such as acquiring a {@link android.bluetooth.BluetoothAdapter}, getting a list of connected
+devices, and checking the state of a device. For example, here's how you should now get the
 {@link android.bluetooth.BluetoothAdapter}:</p>
 <pre>
 final BluetoothManager bluetoothManager =
@@ -362,32 +365,32 @@
 mBluetoothAdapter = bluetoothManager.getAdapter();
 </pre>
 
-<p>To discover Bluetooth LE peripherals, call {@link android.bluetooth.BluetoothAdapter#startLeScan 
-startLeScan()} on the {@link android.bluetooth.BluetoothAdapter}, passing it an implementation 
-of the {@link android.bluetooth.BluetoothAdapter.LeScanCallback} interface. When the Bluetooth 
-adapter detects a Bluetooth LE peripheral, your {@link 
-android.bluetooth.BluetoothAdapter.LeScanCallback} implementation receives a call to the 
-{@link android.bluetooth.BluetoothAdapter.LeScanCallback#onLeScan onLeScan()} method. This 
-method provides you with a {@link android.bluetooth.BluetoothDevice} object representing the 
-detected device, the RSSI value for the device, and a byte array containing the device's 
+<p>To discover Bluetooth LE peripherals, call {@link android.bluetooth.BluetoothAdapter#startLeScan
+startLeScan()} on the {@link android.bluetooth.BluetoothAdapter}, passing it an implementation
+of the {@link android.bluetooth.BluetoothAdapter.LeScanCallback} interface. When the Bluetooth
+adapter detects a Bluetooth LE peripheral, your {@link
+android.bluetooth.BluetoothAdapter.LeScanCallback} implementation receives a call to the
+{@link android.bluetooth.BluetoothAdapter.LeScanCallback#onLeScan onLeScan()} method. This
+method provides you with a {@link android.bluetooth.BluetoothDevice} object representing the
+detected device, the RSSI value for the device, and a byte array containing the device's
 advertisement record.</p>
 
-<p>If you want to scan for only specific types of peripherals, you can instead call {@link 
-android.bluetooth.BluetoothAdapter#startLeScan startLeScan()} and include an array of {@link 
+<p>If you want to scan for only specific types of peripherals, you can instead call {@link
+android.bluetooth.BluetoothAdapter#startLeScan startLeScan()} and include an array of {@link
 java.util.UUID} objects that specify the GATT services your app supports.</p>
 
-<p class="note"><strong>Note:</strong> You can only scan for Bluetooth LE devices <em>or</em> 
-scan for Classic Bluetooth devices using previous APIs. You cannot scan for both LE and Classic 
+<p class="note"><strong>Note:</strong> You can only scan for Bluetooth LE devices <em>or</em>
+scan for Classic Bluetooth devices using previous APIs. You cannot scan for both LE and Classic
 Bluetooth devices at once.</p>
 
-<p>To then connect to a Bluetooth LE peripheral, call {@link 
-android.bluetooth.BluetoothDevice#connectGatt connectGatt()} on the corresponding 
-{@link android.bluetooth.BluetoothDevice} object, passing it an implementation of 
-{@link android.bluetooth.BluetoothGattCallback}. Your implementation of {@link 
-android.bluetooth.BluetoothGattCallback} receives callbacks regarding the connectivity 
-state with the device and other events. It's during the {@link 
-android.bluetooth.BluetoothGattCallback#onConnectionStateChange onConnectionStateChange()} 
-callback that you can begin communicating with the device if the method passes {@link 
+<p>To then connect to a Bluetooth LE peripheral, call {@link
+android.bluetooth.BluetoothDevice#connectGatt connectGatt()} on the corresponding
+{@link android.bluetooth.BluetoothDevice} object, passing it an implementation of
+{@link android.bluetooth.BluetoothGattCallback}. Your implementation of {@link
+android.bluetooth.BluetoothGattCallback} receives callbacks regarding the connectivity
+state with the device and other events. It's during the {@link
+android.bluetooth.BluetoothGattCallback#onConnectionStateChange onConnectionStateChange()}
+callback that you can begin communicating with the device if the method passes {@link
 android.bluetooth.BluetoothProfile#STATE_CONNECTED} as the new state.</p>
 
 <p>Accessing Bluetooth features on a device also requires that your app request certain
@@ -397,39 +400,39 @@
 
 <h3 id="WiFiScan">Wi-Fi scan-only mode</h3>
 
-<p>When attempting to identify the user's location, Android may use Wi-Fi to help determine 
-the location by scanning nearby access points. However, users often keep Wi-Fi turned off to 
-conserve battery, resulting in location data that's less accurate. Android now includes a 
-scan-only mode that allows the device Wi-Fi to scan access points to help obtain the location 
+<p>When attempting to identify the user's location, Android may use Wi-Fi to help determine
+the location by scanning nearby access points. However, users often keep Wi-Fi turned off to
+conserve battery, resulting in location data that's less accurate. Android now includes a
+scan-only mode that allows the device Wi-Fi to scan access points to help obtain the location
 without connecting to an access point, thus greatly reducing battery usage.</p>
 
-<p>If you want to acquire the user's location but Wi-Fi is currently off, you can request the 
-user to enable Wi-Fi scan-only mode by calling {@link android.content.Context#startActivity 
-startActivity()} with the action {@link 
+<p>If you want to acquire the user's location but Wi-Fi is currently off, you can request the
+user to enable Wi-Fi scan-only mode by calling {@link android.content.Context#startActivity
+startActivity()} with the action {@link
 android.net.wifi.WifiManager#ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.</p>
 
 
 <h3 id="WiFiConfig">Wi-Fi configuration</h3>
 
-<p>New {@link android.net.wifi.WifiEnterpriseConfig} APIs allow enterprise-oriented services to 
+<p>New {@link android.net.wifi.WifiEnterpriseConfig} APIs allow enterprise-oriented services to
 automate Wi-Fi configuration for managed devices.</p>
 
 
 <h3 id="QuickResponse">Quick response for incoming calls</h3>
 
-<p>Since Android 4.0, a feature called "Quick response" allows users to respond to incoming 
-calls with an immediate text message without needing to pick up the call or unlock the device. 
-Until now, these quick messages were always handled by the default Messaging app. Now any app 
-can declare its capability to handle these messages by creating a {@link android.app.Service} 
+<p>Since Android 4.0, a feature called "Quick response" allows users to respond to incoming
+calls with an immediate text message without needing to pick up the call or unlock the device.
+Until now, these quick messages were always handled by the default Messaging app. Now any app
+can declare its capability to handle these messages by creating a {@link android.app.Service}
 with an intent filter for {@link android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE}.</p>
 
-<p>When the user responds to an incoming call with a quick response, the Phone app sends 
-the {@link android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE} intent with a URI 
-describing the recipient (the caller) and the {@link android.content.Intent#EXTRA_TEXT} extra 
-with the message the user wants to send. When your service receives the intent, it should deliver 
+<p>When the user responds to an incoming call with a quick response, the Phone app sends
+the {@link android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE} intent with a URI
+describing the recipient (the caller) and the {@link android.content.Intent#EXTRA_TEXT} extra
+with the message the user wants to send. When your service receives the intent, it should deliver
 the message and immediately stop itself (your app should not show an activity).</p>
 
-<p>In order to receive this intent, you must declare the {@link 
+<p>In order to receive this intent, you must declare the {@link
 android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE} permission.</p>
 
 
@@ -438,120 +441,120 @@
 
 <h3 id="DASH">MPEG DASH support</h3>
 
-<p>Android now supports Dynamic Adaptive Streaming over HTTP (DASH) in accordance with the 
-ISO/IEC 23009-1 standard, using existing APIs in {@link android.media.MediaCodec} and {@link 
-android.media.MediaExtractor}. The framework underlying these APIs has been updated to support 
-parsing of fragmented MP4 files, but your app is still responsible for parsing the MPD metadata 
+<p>Android now supports Dynamic Adaptive Streaming over HTTP (DASH) in accordance with the
+ISO/IEC 23009-1 standard, using existing APIs in {@link android.media.MediaCodec} and {@link
+android.media.MediaExtractor}. The framework underlying these APIs has been updated to support
+parsing of fragmented MP4 files, but your app is still responsible for parsing the MPD metadata
 and passing the individual streams to {@link android.media.MediaExtractor}.</p>
 
-<p>If you want to use DASH with encrypted content, notice that the {@link android.media.MediaExtractor#getSampleCryptoInfo getSampleCryptoInfo()} method returns the {@link 
-android.media.MediaCodec.CryptoInfo} metadata describing the structure of each encrypted media 
-sample. Also, the {@link android.media.MediaExtractor#getPsshInfo()} method has been added to 
-{@link android.media.MediaExtractor} so you can access the PSSH metadata for your DASH media. 
-This method returns a map of {@link java.util.UUID} objects to bytes, with the 
-{@link java.util.UUID} specifying the crypto scheme, and the bytes being the data specific 
+<p>If you want to use DASH with encrypted content, notice that the {@link android.media.MediaExtractor#getSampleCryptoInfo getSampleCryptoInfo()} method returns the {@link
+android.media.MediaCodec.CryptoInfo} metadata describing the structure of each encrypted media
+sample. Also, the {@link android.media.MediaExtractor#getPsshInfo()} method has been added to
+{@link android.media.MediaExtractor} so you can access the PSSH metadata for your DASH media.
+This method returns a map of {@link java.util.UUID} objects to bytes, with the
+{@link java.util.UUID} specifying the crypto scheme, and the bytes being the data specific
 to that scheme.</p>
 
 
 <h3 id="DRM">Media DRM</h3>
 
 <p>The new {@link android.media.MediaDrm} class provides a modular solution for digital rights
-management (DRM) with your media content by separating DRM concerns from media playback. For 
-instance, this API separation allows you to play back Widevine-encrypted content without having 
-to use the Widevine media format. This DRM solution also supports DASH Common Encryption so you 
+management (DRM) with your media content by separating DRM concerns from media playback. For
+instance, this API separation allows you to play back Widevine-encrypted content without having
+to use the Widevine media format. This DRM solution also supports DASH Common Encryption so you
 can use a variety of DRM schemes with your streaming content.</p>
 
-<p>You can use {@link android.media.MediaDrm} to obtain opaque key-request messages and process 
-key-response messages from the server for license acquisition and provisioning. Your app is 
-responsible for handling the network communication with the servers; the {@link 
+<p>You can use {@link android.media.MediaDrm} to obtain opaque key-request messages and process
+key-response messages from the server for license acquisition and provisioning. Your app is
+responsible for handling the network communication with the servers; the {@link
 android.media.MediaDrm} class provides only the ability to generate and process the messages.</p>
 
-<p>The {@link android.media.MediaDrm} APIs are  intended to be used in conjunction with the 
-{@link android.media.MediaCodec} APIs that were introduced in Android 4.1 (API level 16), 
-including {@link android.media.MediaCodec} for encoding and decoding your content, {@link 
-android.media.MediaCrypto} for handling encrypted content, and {@link android.media.MediaExtractor} 
+<p>The {@link android.media.MediaDrm} APIs are  intended to be used in conjunction with the
+{@link android.media.MediaCodec} APIs that were introduced in Android 4.1 (API level 16),
+including {@link android.media.MediaCodec} for encoding and decoding your content, {@link
+android.media.MediaCrypto} for handling encrypted content, and {@link android.media.MediaExtractor}
 for extracting and demuxing your content.</p>
 
-<p>You must first construct {@link android.media.MediaExtractor} and 
-{@link android.media.MediaCodec} objects. You can then access the DRM-scheme-identifying 
-{@link java.util.UUID}, typically from metadata in the content, and use it to construct an 
+<p>You must first construct {@link android.media.MediaExtractor} and
+{@link android.media.MediaCodec} objects. You can then access the DRM-scheme-identifying
+{@link java.util.UUID}, typically from metadata in the content, and use it to construct an
 instance of a {@link android.media.MediaDrm} object with its constructor.</p>
 
 
 <h3 id="EncodingSurface">Video encoding from a Surface</h3>
 
-<p>Android 4.1 (API level 16) added the {@link android.media.MediaCodec} class for low-level 
-encoding and decoding of media content. When encoding video, Android 4.1 required that you provide 
-the media with a {@link java.nio.ByteBuffer} array, but Android 4.3 now allows you to use a {@link 
-android.view.Surface} as the input to an encoder. For instance, this allows you to encode input 
+<p>Android 4.1 (API level 16) added the {@link android.media.MediaCodec} class for low-level
+encoding and decoding of media content. When encoding video, Android 4.1 required that you provide
+the media with a {@link java.nio.ByteBuffer} array, but Android 4.3 now allows you to use a {@link
+android.view.Surface} as the input to an encoder. For instance, this allows you to encode input
 from an existing video file or using frames generated from OpenGL ES.</p>
 
-<p>To use a {@link android.view.Surface} as the input to your encoder, first call {@link 
-android.media.MediaCodec#configure configure()} for your {@link android.media.MediaCodec}. 
-Then call {@link android.media.MediaCodec#createInputSurface()} to receive the {@link 
+<p>To use a {@link android.view.Surface} as the input to your encoder, first call {@link
+android.media.MediaCodec#configure configure()} for your {@link android.media.MediaCodec}.
+Then call {@link android.media.MediaCodec#createInputSurface()} to receive the {@link
 android.view.Surface} upon which you can stream your media.</p>
 
-<p>For example, you can use the given {@link android.view.Surface} as the window for an OpenGL 
-context by passing it to {@link android.opengl.EGL14#eglCreateWindowSurface 
-eglCreateWindowSurface()}. Then while rendering the surface, call {@link 
-android.opengl.EGL14#eglSwapBuffers eglSwapBuffers()} to pass the frame to the {@link 
+<p>For example, you can use the given {@link android.view.Surface} as the window for an OpenGL
+context by passing it to {@link android.opengl.EGL14#eglCreateWindowSurface
+eglCreateWindowSurface()}. Then while rendering the surface, call {@link
+android.opengl.EGL14#eglSwapBuffers eglSwapBuffers()} to pass the frame to the {@link
 android.media.MediaCodec}.</p>
 
-<p>To begin encoding, call {@link android.media.MediaCodec#start()} on the {@link 
-android.media.MediaCodec}. When done, call {@link android.media.MediaCodec#signalEndOfInputStream} 
-to terminate encoding, and call {@link android.view.Surface#release()} on the 
+<p>To begin encoding, call {@link android.media.MediaCodec#start()} on the {@link
+android.media.MediaCodec}. When done, call {@link android.media.MediaCodec#signalEndOfInputStream}
+to terminate encoding, and call {@link android.view.Surface#release()} on the
 {@link android.view.Surface}.</p>
 
 
 <h3 id="MediaMuxing">Media muxing</h3>
 
-<p>The new {@link android.media.MediaMuxer} class enables multiplexing between one audio stream 
-and one video stream. These APIs serve as a counterpart to the {@link android.media.MediaExtractor} 
+<p>The new {@link android.media.MediaMuxer} class enables multiplexing between one audio stream
+and one video stream. These APIs serve as a counterpart to the {@link android.media.MediaExtractor}
 class added in Android 4.2 for de-multiplexing (demuxing) media.</p>
 
-<p>Supported output formats are defined in {@link android.media.MediaMuxer.OutputFormat}. Currently, 
-MP4 is the only supported output format and {@link android.media.MediaMuxer} currently supports 
+<p>Supported output formats are defined in {@link android.media.MediaMuxer.OutputFormat}. Currently,
+MP4 is the only supported output format and {@link android.media.MediaMuxer} currently supports
 only one audio stream and/or one video stream at a time.</p>
 
-<p>{@link android.media.MediaMuxer} is mostly designed to work with {@link android.media.MediaCodec} 
-so you can perform video processing through {@link android.media.MediaCodec} then save the 
-output to an MP4 file through {@link android.media.MediaMuxer}. You can also use {@link 
-android.media.MediaMuxer} in combination with {@link android.media.MediaExtractor} to perform 
+<p>{@link android.media.MediaMuxer} is mostly designed to work with {@link android.media.MediaCodec}
+so you can perform video processing through {@link android.media.MediaCodec} then save the
+output to an MP4 file through {@link android.media.MediaMuxer}. You can also use {@link
+android.media.MediaMuxer} in combination with {@link android.media.MediaExtractor} to perform
 media editing without the need to encode or decode.</p>
 
 
 <h3 id="ProgressAndScrubbing">Playback progress and scrubbing for RemoteControlClient</h3>
 
-<p>In Android 4.0 (API level 14), the {@link android.media.RemoteControlClient} was added to 
-enable media playback controls from remote control clients such as the controls available on the 
-lock screen. Android 4.3 now provides the ability for such controllers to display the playback 
-position and controls for scrubbing the playback. If you've enabled remote control for your 
-media app with the {@link android.media.RemoteControlClient} APIs, then you can allow playback 
+<p>In Android 4.0 (API level 14), the {@link android.media.RemoteControlClient} was added to
+enable media playback controls from remote control clients such as the controls available on the
+lock screen. Android 4.3 now provides the ability for such controllers to display the playback
+position and controls for scrubbing the playback. If you've enabled remote control for your
+media app with the {@link android.media.RemoteControlClient} APIs, then you can allow playback
 scrubbing by implementing two new interfaces.</p>
 
-<p>First, you must enable the {@link 
-android.media.RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE} flag by passing it to 
-{@link android.media.RemoteControlClient#setTransportControlFlags setTransportControlsFlags()}.</p> 
+<p>First, you must enable the {@link
+android.media.RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE} flag by passing it to
+{@link android.media.RemoteControlClient#setTransportControlFlags setTransportControlsFlags()}.</p>
 
 <p>Then implement the following two new interfaces:</p>
 <dl>
   <dt>{@link android.media.RemoteControlClient.OnGetPlaybackPositionListener}</dt>
-  <dd>This includes the callback {@link android.media.RemoteControlClient.OnGetPlaybackPositionListener#onGetPlaybackPosition}, which requests the current position 
+  <dd>This includes the callback {@link android.media.RemoteControlClient.OnGetPlaybackPositionListener#onGetPlaybackPosition}, which requests the current position
   of your media when the remote control needs to update the progress in its UI.</dd>
 
   <dt>{@link android.media.RemoteControlClient.OnPlaybackPositionUpdateListener}</dt>
-  <dd>This includes the callback {@link android.media.RemoteControlClient.OnPlaybackPositionUpdateListener#onPlaybackPositionUpdate onPlaybackPositionUpdate()}, which 
-  tells your app the new time code for your media when the user scrubs the playback with the 
+  <dd>This includes the callback {@link android.media.RemoteControlClient.OnPlaybackPositionUpdateListener#onPlaybackPositionUpdate onPlaybackPositionUpdate()}, which
+  tells your app the new time code for your media when the user scrubs the playback with the
   remote control UI.
-    <p>Once you update your playback with the new position, call {@link 
-    android.media.RemoteControlClient#setPlaybackState setPlaybackState()} to indicate the 
+    <p>Once you update your playback with the new position, call {@link
+    android.media.RemoteControlClient#setPlaybackState setPlaybackState()} to indicate the
     new playback state, position, and speed.</p>
   </dd>
 </dl>
 
-<p>With these interfaces defined, you can set them for your {@link 
-android.media.RemoteControlClient} by calling {@link android.media.RemoteControlClient#setOnGetPlaybackPositionListener setOnGetPlaybackPositionListener()} and 
-{@link android.media.RemoteControlClient#setPlaybackPositionUpdateListener 
+<p>With these interfaces defined, you can set them for your {@link
+android.media.RemoteControlClient} by calling {@link android.media.RemoteControlClient#setOnGetPlaybackPositionListener setOnGetPlaybackPositionListener()} and
+{@link android.media.RemoteControlClient#setPlaybackPositionUpdateListener
 setPlaybackPositionUpdateListener()}, respectively.</p>
 
 
@@ -560,7 +563,7 @@
 
 <h3 id="OpenGL">Support for OpenGL ES 3.0</h3>
 
-<p>Android 4.3 adds Java interfaces and native support for OpenGL ES 3.0. Key new functionality 
+<p>Android 4.3 adds Java interfaces and native support for OpenGL ES 3.0. Key new functionality
 provided in OpenGL ES 3.0 includes:</p>
 <ul>
   <li>Acceleration of advanced visual effects</li>
@@ -570,8 +573,8 @@
   <li>Broader standardization of texture size and render-buffer formats</li>
 </ul>
 
-<p>The Java interface for OpenGL ES 3.0 on Android is provided with {@link android.opengl.GLES30}. 
-When using OpenGL ES 3.0, be sure that you declare it in your manifest file with the 
+<p>The Java interface for OpenGL ES 3.0 on Android is provided with {@link android.opengl.GLES30}.
+When using OpenGL ES 3.0, be sure that you declare it in your manifest file with the
 <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature></a>
 tag and the {@code android:glEsVersion} attribute. For example:</p>
 <pre>
@@ -586,16 +589,16 @@
 
 <h3 id="MipMap">Mipmapping for drawables</h3>
 
-<p>Using a mipmap as the source for your bitmap or drawable is a simple way to provide a 
-quality image and various image scales, which can be particularly useful if you expect your 
+<p>Using a mipmap as the source for your bitmap or drawable is a simple way to provide a
+quality image and various image scales, which can be particularly useful if you expect your
 image to be scaled during an animation.</p>
 
-<p>Android 4.2 (API level 17) added support for mipmaps in the {@link android.graphics.Bitmap} 
-class&mdash;Android swaps the mip images in your {@link android.graphics.Bitmap} when you've 
-supplied a mipmap source and have enabled {@link android.graphics.Bitmap#setHasMipMap 
-setHasMipMap()}. Now in Android 4.3, you can enable mipmaps for a {@link 
-android.graphics.drawable.BitmapDrawable} object as well, by providing a mipmap asset and 
-setting the {@code android:mipMap} attribute in a bitmap resource file or by calling {@link 
+<p>Android 4.2 (API level 17) added support for mipmaps in the {@link android.graphics.Bitmap}
+class&mdash;Android swaps the mip images in your {@link android.graphics.Bitmap} when you've
+supplied a mipmap source and have enabled {@link android.graphics.Bitmap#setHasMipMap
+setHasMipMap()}. Now in Android 4.3, you can enable mipmaps for a {@link
+android.graphics.drawable.BitmapDrawable} object as well, by providing a mipmap asset and
+setting the {@code android:mipMap} attribute in a bitmap resource file or by calling {@link
 android.graphics.drawable.BitmapDrawable#hasMipMap hasMipMap()}.
 </p>
 
@@ -605,36 +608,36 @@
 
 <h3 id="ViewOverlay">View overlays</h3>
 
-<p>The new {@link android.view.ViewOverlay} class provides a transparent layer on top of 
-a {@link android.view.View} on which you can add visual content and which does not affect 
-the layout hierarchy. You can get a {@link android.view.ViewOverlay} for any {@link 
-android.view.View} by calling {@link android.view.View#getOverlay}. The overlay 
-always has the same size and position as its host view (the view from which it was created), 
-allowing you to add content that appears in front of the host view, but which cannot extend 
+<p>The new {@link android.view.ViewOverlay} class provides a transparent layer on top of
+a {@link android.view.View} on which you can add visual content and which does not affect
+the layout hierarchy. You can get a {@link android.view.ViewOverlay} for any {@link
+android.view.View} by calling {@link android.view.View#getOverlay}. The overlay
+always has the same size and position as its host view (the view from which it was created),
+allowing you to add content that appears in front of the host view, but which cannot extend
 the bounds of that host view.
 </p>
 
-<p>Using a {@link android.view.ViewOverlay} is particularly useful when you want to create 
-animations such as sliding a view outside of its container or moving items around the screen 
-without affecting the view hierarchy. However, because the usable area of an overlay is 
-restricted to the same area as its host view, if you want to animate a view moving outside 
-its position in the layout, you must use an overlay from a parent view that has the desired 
+<p>Using a {@link android.view.ViewOverlay} is particularly useful when you want to create
+animations such as sliding a view outside of its container or moving items around the screen
+without affecting the view hierarchy. However, because the usable area of an overlay is
+restricted to the same area as its host view, if you want to animate a view moving outside
+its position in the layout, you must use an overlay from a parent view that has the desired
 layout bounds.</p>
 
-<p>When you create an overlay for a widget view such as a {@link android.widget.Button}, you 
-can add {@link android.graphics.drawable.Drawable} objects to the overlay by calling 
-{@link android.view.ViewOverlay#add(Drawable)}. If you call {@link 
+<p>When you create an overlay for a widget view such as a {@link android.widget.Button}, you
+can add {@link android.graphics.drawable.Drawable} objects to the overlay by calling
+{@link android.view.ViewOverlay#add(Drawable)}. If you call {@link
 android.view.ViewGroup#getOverlay} for a layout view, such as {@link android.widget.RelativeLayout},
 the object returned is a {@link android.view.ViewGroupOverlay}. The
-{@link android.view.ViewGroupOverlay} class is a subclass 
-of {@link android.view.ViewOverlay} that  also allows you to add {@link android.view.View} 
+{@link android.view.ViewGroupOverlay} class is a subclass
+of {@link android.view.ViewOverlay} that  also allows you to add {@link android.view.View}
 objects by calling {@link android.view.ViewGroupOverlay#add(View)}.
 </p>
 
-<p class="note"><strong>Note:</strong> All drawables and views that you add to an overlay 
+<p class="note"><strong>Note:</strong> All drawables and views that you add to an overlay
 are visual only. They cannot receive focus or input events.</p>
 
-<p>For example, the following code animates a view sliding to the right by placing the view 
+<p>For example, the following code animates a view sliding to the right by placing the view
 in the parent view's overlay, then performing a translation animation on that view:</p>
 <pre>
 View view = findViewById(R.id.view_to_remove);
@@ -647,17 +650,17 @@
 
 <h3 id="OpticalBounds">Optical bounds layout</h3>
 
-<p>For views that contain nine-patch background images, you can now specify that they should 
-be aligned with neighboring views based on the "optical" bounds of the background image rather 
+<p>For views that contain nine-patch background images, you can now specify that they should
+be aligned with neighboring views based on the "optical" bounds of the background image rather
 than the "clip" bounds of the view.</p>
 
-<p>For example, figures 1 and 2 each show the same layout, but the version in figure 1 is 
-using clip bounds (the default behavior), while figure 2 is using optical bounds. Because the 
-nine-patch images used for the button and the photo frame include padding around the edges, 
+<p>For example, figures 1 and 2 each show the same layout, but the version in figure 1 is
+using clip bounds (the default behavior), while figure 2 is using optical bounds. Because the
+nine-patch images used for the button and the photo frame include padding around the edges,
 they don’t appear to align with each other or the text when using clip bounds.</p>
 
-<p class="note"><strong>Note:</strong> The screenshot in figures 1 and 2 have the "Show 
-layout bounds" developer setting enabled. For each view, red lines indicate the optical 
+<p class="note"><strong>Note:</strong> The screenshot in figures 1 and 2 have the "Show
+layout bounds" developer setting enabled. For each view, red lines indicate the optical
 bounds, blue lines indicate the clip bounds, and pink indicates margins.</p>
 
 <script type="text/javascript">
@@ -725,30 +728,30 @@
 </p>
 </div>
 
-<p>For this to work, the nine-patch images applied to the background of your views must specify 
-the optical bounds using red lines along the bottom and right-side of the nine-patch file (as 
-shown in figure 3). The red lines indicate the region that should be subtracted from 
+<p>For this to work, the nine-patch images applied to the background of your views must specify
+the optical bounds using red lines along the bottom and right-side of the nine-patch file (as
+shown in figure 3). The red lines indicate the region that should be subtracted from
 the clip bounds, leaving the optical bounds of the image.</p>
 
-<p>When you enable optical bounds for a {@link android.view.ViewGroup} in your layout, all 
-descendant views inherit the optical bounds layout mode unless you override it for a group by 
-setting {@code android:layoutMode} to {@code "clipBounds"}. All layout elements also honor the 
-optical bounds of their child views, adapting their own bounds based on the optical bounds of 
-the views within them. However, layout elements (subclasses of {@link android.view.ViewGroup}) 
+<p>When you enable optical bounds for a {@link android.view.ViewGroup} in your layout, all
+descendant views inherit the optical bounds layout mode unless you override it for a group by
+setting {@code android:layoutMode} to {@code "clipBounds"}. All layout elements also honor the
+optical bounds of their child views, adapting their own bounds based on the optical bounds of
+the views within them. However, layout elements (subclasses of {@link android.view.ViewGroup})
 currently do not support optical bounds for nine-patch images applied to their own background.</p>
 
 <p>If you create a custom view by subclassing {@link android.view.View}, {@link android.view.ViewGroup}, or any subclasses thereof, your view will inherit these optical bound behaviors.</p>
 
 <p class="note"><strong>Note:</strong> All widgets supported by the Holo theme have been updated
-with optical bounds, including {@link android.widget.Button},  {@link android.widget.Spinner}, 
+with optical bounds, including {@link android.widget.Button},  {@link android.widget.Spinner},
 {@link android.widget.EditText}, and others. So you can immediately benefit by setting the
-{@code android:layoutMode} attribute to {@code "opticalBounds"} if your app applies a Holo theme 
-({@link android.R.style#Theme_Holo Theme.Holo}, {@link android.R.style#Theme_Holo_Light 
+{@code android:layoutMode} attribute to {@code "opticalBounds"} if your app applies a Holo theme
+({@link android.R.style#Theme_Holo Theme.Holo}, {@link android.R.style#Theme_Holo_Light
 Theme.Holo.Light}, etc.).
 </p>
 
-<p>To specify optical bounds for your own nine-patch images with the <a 
-href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool, hold CTRL when clicking on 
+<p>To specify optical bounds for your own nine-patch images with the <a
+href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool, hold CTRL when clicking on
 the border pixels.</p>
 
 
@@ -756,59 +759,59 @@
 
 <h3 id="AnimationRect">Animation for Rect values</h3>
 
-<p>You can now animate between two {@link android.graphics.Rect} values with the new {@link 
-android.animation.RectEvaluator}. This new class is an implementation of {@link 
-android.animation.TypeEvaluator} that you can pass to {@link 
+<p>You can now animate between two {@link android.graphics.Rect} values with the new {@link
+android.animation.RectEvaluator}. This new class is an implementation of {@link
+android.animation.TypeEvaluator} that you can pass to {@link
 android.animation.ValueAnimator#setEvaluator ValueAnimator.setEvaluator()}.
 </p>
 
 <h3 id="AttachFocus">Window attach and focus listener</h3>
 
-<p>Previously, if you wanted to listen for when your view attached/detached to the window or 
-when its focus changed, you needed to override the {@link android.view.View} class to 
-implement {@link android.view.View#onAttachedToWindow onAttachedToWindow()} and {@link 
-android.view.View#onDetachedFromWindow onDetachedFromWindow()}, or  {@link 
+<p>Previously, if you wanted to listen for when your view attached/detached to the window or
+when its focus changed, you needed to override the {@link android.view.View} class to
+implement {@link android.view.View#onAttachedToWindow onAttachedToWindow()} and {@link
+android.view.View#onDetachedFromWindow onDetachedFromWindow()}, or  {@link
 android.view.View#onWindowFocusChanged onWindowFocusChanged()}, respectively.
 </p>
 
-<p>Now, to receive attach and detach events you can instead implement {@link 
-android.view.ViewTreeObserver.OnWindowAttachListener} and set it on a view with 
-{@link android.view.ViewTreeObserver#addOnWindowAttachListener addOnWindowAttachListener()}. 
-And to receive focus events, you can implement {@link 
-android.view.ViewTreeObserver.OnWindowFocusChangeListener} and set it on a view with 
-{@link android.view.ViewTreeObserver#addOnWindowFocusChangeListener 
+<p>Now, to receive attach and detach events you can instead implement {@link
+android.view.ViewTreeObserver.OnWindowAttachListener} and set it on a view with
+{@link android.view.ViewTreeObserver#addOnWindowAttachListener addOnWindowAttachListener()}.
+And to receive focus events, you can implement {@link
+android.view.ViewTreeObserver.OnWindowFocusChangeListener} and set it on a view with
+{@link android.view.ViewTreeObserver#addOnWindowFocusChangeListener
 addOnWindowFocusChangeListener()}.
 </p>
 
 
 <h3 id="Overscan">TV overscan support</h3>
 
-<p>To be sure your app fills the entire screen on every television, you can now enable overscan 
-for you app layout. Overscan mode is determined by the {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag, which you can enable with platform themes such as 
-{@link android.R.style#Theme_DeviceDefault_NoActionBar_Overscan} or by enabling the 
+<p>To be sure your app fills the entire screen on every television, you can now enable overscan
+for you app layout. Overscan mode is determined by the {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag, which you can enable with platform themes such as
+{@link android.R.style#Theme_DeviceDefault_NoActionBar_Overscan} or by enabling the
 {@link android.R.attr#windowOverscan} style in a custom theme.</p>
 
 
 <h3 id="Orientation">Screen orientation</h3>
 
-<p>The <a 
+<p>The <a
 href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity>}</a>
-tag's <a 
+tag's <a
 href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code screenOrientation}</a>
 attribute now supports additional values to honor the user's preference for auto-rotation:</p>
 <dl>
 <dt>{@code "userLandscape"}</dt>
-<dd>Behaves the same as {@code "sensorLandscape"}, except if the user disables auto-rotate 
+<dd>Behaves the same as {@code "sensorLandscape"}, except if the user disables auto-rotate
 then it locks in the normal landscape orientation and will not flip.
 </dd>
 
 <dt>{@code "userPortrait"}</dt>
-<dd>Behaves the same as {@code "sensorPortrait"}, except if the user disables auto-rotate then 
+<dd>Behaves the same as {@code "sensorPortrait"}, except if the user disables auto-rotate then
 it locks in the normal portrait orientation and will not flip.
 </dd>
 
 <dt>{@code "fullUser"}</dt>
-<dd>Behaves the same as {@code "fullSensor"} and allows rotation in all four directions, except 
+<dd>Behaves the same as {@code "fullSensor"} and allows rotation in all four directions, except
 if the user disables auto-rotate then it locks in the user's preferred orientation.
 </dd></dl>
 
@@ -818,8 +821,8 @@
 
 <h3 id="RotationAnimation">Rotation animations</h3>
 
-<p>The new {@link android.view.WindowManager.LayoutParams#rotationAnimation} field in 
-{@link android.view.WindowManager} allows you to select between one of three animations you 
+<p>The new {@link android.view.WindowManager.LayoutParams#rotationAnimation} field in
+{@link android.view.WindowManager} allows you to select between one of three animations you
 want to use when the system switches screen orientations. The three animations are:</p>
 <ul>
   <li>{@link android.view.WindowManager.LayoutParams#ROTATION_ANIMATION_CROSSFADE}</li>
@@ -844,25 +847,17 @@
 
 <h2 id="UserInput">User Input</h2>
 
-<h3 id="SignificantMotion">Detect significant motion</h3>
-
-<p>The {@link android.hardware.SensorManager} APIs now allow you to request a callback when the 
-device sensors detect "significant motion." For instance, this event may be triggered by new 
-motion such as when the user starts to walk.</p>
-
-<p>To register a listener for significant motion, extend the {@link android.hardware.TriggerEventListener} class and implement the {@link android.hardware.TriggerEventListener#onTrigger onTrigger()} callback method. Then register your event listener with the {@link android.hardware.SensorManager} by passing it to {@link android.hardware.SensorManager#requestTriggerSensor requestTriggerSensor()}, passing it your {@link android.hardware.TriggerEventListener} and {@link android.hardware.Sensor#TYPE_SIGNIFICANT_MOTION}.</p>
-
 <h3 id="Sensors">New sensor types</h3>
 <p>The new {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR} sensor allows you to detect the device's rotations without worrying about magnetic interferences. Unlike the {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR} sensor, the {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR} is not based on magnetic north.</p>
 
-<p>The new {@link android.hardware.Sensor#TYPE_GYROSCOPE_UNCALIBRATED} and {@link 
-android.hardware.Sensor#TYPE_MAGNETIC_FIELD_UNCALIBRATED} sensors provide raw sensor data without 
-consideration for bias estimations. That is, the existing {@link 
-android.hardware.Sensor#TYPE_GYROSCOPE} and {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD} 
-sensors provide sensor data that takes into account estimated bias from gyro-drift and hard iron 
-in the device, respectively. Whereas the new "uncalibrated" versions of these sensors instead provide 
-the raw sensor data and offer the estimated bias values separately. These sensors allow you to 
-provide your own custom calibration for the sensor data by enhancing the estimated bias with 
+<p>The new {@link android.hardware.Sensor#TYPE_GYROSCOPE_UNCALIBRATED} and {@link
+android.hardware.Sensor#TYPE_MAGNETIC_FIELD_UNCALIBRATED} sensors provide raw sensor data without
+consideration for bias estimations. That is, the existing {@link
+android.hardware.Sensor#TYPE_GYROSCOPE} and {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD}
+sensors provide sensor data that takes into account estimated bias from gyro-drift and hard iron
+in the device, respectively. Whereas the new "uncalibrated" versions of these sensors instead provide
+the raw sensor data and offer the estimated bias values separately. These sensors allow you to
+provide your own custom calibration for the sensor data by enhancing the estimated bias with
 external data.</p>
 
 
@@ -891,13 +886,13 @@
 
 <p>To track which contacts have been deleted, the new table {@link android.provider.ContactsContract.DeletedContacts} provides a log of contacts that have been deleted (but each contact deleted is held in this table for a limited time). Similar to {@link android.provider.ContactsContract.ContactsColumns#CONTACT_LAST_UPDATED_TIMESTAMP}, you can use the new selection parameter, {@link android.provider.ContactsContract.DeletedContacts#CONTACT_DELETED_TIMESTAMP} to check which contacts have been deleted since the last time you queried the provider. The table also contains the constant {@link android.provider.ContactsContract.DeletedContacts#DAYS_KEPT_MILLISECONDS} containing the number of days (in milliseconds) that the log will be kept.</p>
 
-<p>Additionally, the Contacts Provider now broadcasts the {@link 
-android.provider.ContactsContract.Intents#CONTACTS_DATABASE_CREATED} action when the user 
-clears the contacts storage through the system settings menu, effectively recreating the 
-Contacts Provider database. It’s intended to signal apps that they need to drop all the contact 
+<p>Additionally, the Contacts Provider now broadcasts the {@link
+android.provider.ContactsContract.Intents#CONTACTS_DATABASE_CREATED} action when the user
+clears the contacts storage through the system settings menu, effectively recreating the
+Contacts Provider database. It’s intended to signal apps that they need to drop all the contact
 information they’ve stored and reload it with a new query.</p>
 
-<p>For sample code using these APIs to check for changes to the contacts, look in the ApiDemos 
+<p>For sample code using these APIs to check for changes to the contacts, look in the ApiDemos
 sample available in the <a href="{@docRoot}tools/samples/index.html">SDK Samples</a> download.</p>
 
 
@@ -905,13 +900,13 @@
 
 <h3 id="BiDi">Improved support for bi-directional text</h3>
 
-<p>Previous versions of Android support right-to-left (RTL) languages and layout, 
-but sometimes don't properly handle mixed-direction text. So Android 4.3 adds the {@link 
-android.text.BidiFormatter} APIs that help you properly format text with opposite-direction 
+<p>Previous versions of Android support right-to-left (RTL) languages and layout,
+but sometimes don't properly handle mixed-direction text. So Android 4.3 adds the {@link
+android.text.BidiFormatter} APIs that help you properly format text with opposite-direction
 content without garbling any parts of it.</p>
 
-<p>For example, when you want to create a sentence with a string variable, such as "Did you mean 
-15 Bay Street, Laurel, CA?", you normally pass a localized string resource and the variable to 
+<p>For example, when you want to create a sentence with a string variable, such as "Did you mean
+15 Bay Street, Laurel, CA?", you normally pass a localized string resource and the variable to
 {@link java.lang.String#format String.format()}:</p>
 <pre>
 Resources res = getResources();
@@ -922,8 +917,8 @@
 
 <p dir="rtl">האם התכוונת ל 15 Bay Street, Laurel, CA?</p>
 
-<p>That's wrong because the "15" should be left of "Bay Street." The solution is to use {@link 
-android.text.BidiFormatter} and its {@link android.text.BidiFormatter#unicodeWrap(String) 
+<p>That's wrong because the "15" should be left of "Bay Street." The solution is to use {@link
+android.text.BidiFormatter} and its {@link android.text.BidiFormatter#unicodeWrap(String)
 unicodeWrap()} method. For example, the code above becomes:</p>
 <pre>
 Resources res = getResources();
@@ -933,11 +928,11 @@
 </pre>
 
 <p>
-By default, {@link android.text.BidiFormatter#unicodeWrap(String) unicodeWrap()} uses the 
-first-strong directionality estimation heuristic, which can get things wrong if the first 
-signal for text direction does not represent the appropriate direction for the content as a whole. 
-If necessary, you can specify a different heuristic by passing one of the {@link 
-android.text.TextDirectionHeuristic} constants from {@link android.text.TextDirectionHeuristics} 
+By default, {@link android.text.BidiFormatter#unicodeWrap(String) unicodeWrap()} uses the
+first-strong directionality estimation heuristic, which can get things wrong if the first
+signal for text direction does not represent the appropriate direction for the content as a whole.
+If necessary, you can specify a different heuristic by passing one of the {@link
+android.text.TextDirectionHeuristic} constants from {@link android.text.TextDirectionHeuristics}
 to {@link android.text.BidiFormatter#unicodeWrap(String,TextDirectionHeuristic) unicodeWrap()}.</p>
 
 <p class="note"><strong>Note:</strong> These new APIs are also available for previous versions
@@ -950,31 +945,31 @@
 
 <h3 id="A11yKeyEvents">Handle key events</h3>
 
-<p>An {@link android.accessibilityservice.AccessibilityService} can now receive a callback for 
-key input events with the {@link android.accessibilityservice.AccessibilityService#onKeyEvent 
-onKeyEvent()} callback method. This allows your accessibility service to handle input for 
-key-based input devices such as a keyboard and translate those events to special actions that 
+<p>An {@link android.accessibilityservice.AccessibilityService} can now receive a callback for
+key input events with the {@link android.accessibilityservice.AccessibilityService#onKeyEvent
+onKeyEvent()} callback method. This allows your accessibility service to handle input for
+key-based input devices such as a keyboard and translate those events to special actions that
 previously may have been possible only with touch input or the device's directional pad.</p>
 
 
 <h3 id="A11yText">Select text and copy/paste</h3>
 
-<p>The {@link android.view.accessibility.AccessibilityNodeInfo} now provides APIs that allow 
-an {@link android.accessibilityservice.AccessibilityService} to select, cut, copy, and paste 
+<p>The {@link android.view.accessibility.AccessibilityNodeInfo} now provides APIs that allow
+an {@link android.accessibilityservice.AccessibilityService} to select, cut, copy, and paste
 text in a node.</p>
 
-<p>To specify the selection of text to cut or copy, your accessibility service can use the new 
-action, {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_SET_SELECTION}, passing 
-with it the selection start and end position with {@link 
-android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT} and {@link 
-android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT}. 
-Alternatively you can select text by manipulating the cursor position using the existing 
-action, {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY} 
-(previously only for moving the cursor position), and adding the argument {@link 
+<p>To specify the selection of text to cut or copy, your accessibility service can use the new
+action, {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_SET_SELECTION}, passing
+with it the selection start and end position with {@link
+android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT} and {@link
+android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT}.
+Alternatively you can select text by manipulating the cursor position using the existing
+action, {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}
+(previously only for moving the cursor position), and adding the argument {@link
 android.view.accessibility.AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}.</p>
 
-<p>You can then cut or copy with {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_CUT}, 
-{@link android.view.accessibility.AccessibilityNodeInfo#ACTION_COPY}, then later paste with 
+<p>You can then cut or copy with {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_CUT},
+{@link android.view.accessibility.AccessibilityNodeInfo#ACTION_COPY}, then later paste with
 {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_PASTE}.</p>
 
 
@@ -987,14 +982,14 @@
 
 <h3 id="A11yFeatures">Declare accessibility features</h3>
 
-<p>Beginning with Android 4.3, an accessibility service must declare accessibility capabilities 
-in its metadata file in order to use certain accessibility features. If the capability is not 
-requested in the metadata file, then the feature will be a no-op. To declare your service's 
-accessibility capabilities, you must use XML attributes that correspond to the various 
-"capability" constants in the {@link android.accessibilityservice.AccessibilityServiceInfo} 
+<p>Beginning with Android 4.3, an accessibility service must declare accessibility capabilities
+in its metadata file in order to use certain accessibility features. If the capability is not
+requested in the metadata file, then the feature will be a no-op. To declare your service's
+accessibility capabilities, you must use XML attributes that correspond to the various
+"capability" constants in the {@link android.accessibilityservice.AccessibilityServiceInfo}
 class.</p>
 
-<p>For example, if a service does not request the {@link android.R.styleable#AccessibilityService_canRequestFilterKeyEvents flagRequestFilterKeyEvents} capability, 
+<p>For example, if a service does not request the {@link android.R.styleable#AccessibilityService_canRequestFilterKeyEvents flagRequestFilterKeyEvents} capability,
 then it will not receive key events.</p>
 
 
@@ -1002,36 +997,36 @@
 
 <h3 id="UiAutomation">Automated UI testing</h3>
 
-<p>The new {@link android.app.UiAutomation} class provides APIs that allow you to simulate user 
-actions for test automation. By using the platform's {@link 
-android.accessibilityservice.AccessibilityService} APIs, the {@link android.app.UiAutomation} 
+<p>The new {@link android.app.UiAutomation} class provides APIs that allow you to simulate user
+actions for test automation. By using the platform's {@link
+android.accessibilityservice.AccessibilityService} APIs, the {@link android.app.UiAutomation}
 APIs allow you to inspect the screen content and inject arbitrary keyboard and touch events.</p>
 
-<p>To get an instance of {@link android.app.UiAutomation}, call {@link 
-android.app.Instrumentation#getUiAutomation Instrumentation.getUiAutomation()}. In order 
-for this to work, you must supply the {@code -w} option with the {@code instrument} command 
-when running your {@link android.test.InstrumentationTestCase} from <a 
+<p>To get an instance of {@link android.app.UiAutomation}, call {@link
+android.app.Instrumentation#getUiAutomation Instrumentation.getUiAutomation()}. In order
+for this to work, you must supply the {@code -w} option with the {@code instrument} command
+when running your {@link android.test.InstrumentationTestCase} from <a
 href="{@docRoot}tools/help/adb.html#am">{@code adb shell}</a>.</p>
 
-<p>With the {@link android.app.UiAutomation} instance, you can execute arbitrary events to test 
-your app by calling {@link android.app.UiAutomation#executeAndWaitForEvent 
-executeAndWaitForEvent()}, passing it a {@link java.lang.Runnable} to perform, a timeout 
-period for the operation, and an implementation of the {@link 
-android.app.UiAutomation.AccessibilityEventFilter} interface. It's within your {@link 
-android.app.UiAutomation.AccessibilityEventFilter} implementation that you'll receive a call 
-that allows you to filter the events that you're interested in and determine the success or 
+<p>With the {@link android.app.UiAutomation} instance, you can execute arbitrary events to test
+your app by calling {@link android.app.UiAutomation#executeAndWaitForEvent
+executeAndWaitForEvent()}, passing it a {@link java.lang.Runnable} to perform, a timeout
+period for the operation, and an implementation of the {@link
+android.app.UiAutomation.AccessibilityEventFilter} interface. It's within your {@link
+android.app.UiAutomation.AccessibilityEventFilter} implementation that you'll receive a call
+that allows you to filter the events that you're interested in and determine the success or
 failure of a given test case.</p>
 
-<p>To observe all the events during a test, create an implementation of {@link 
-android.app.UiAutomation.OnAccessibilityEventListener} and pass it to {@link 
-android.app.UiAutomation#setOnAccessibilityEventListener setOnAccessibilityEventListener()}.  
-Your listener interface then receives a call to {@link 
-android.app.UiAutomation.OnAccessibilityEventListener#onAccessibilityEvent onAccessibilityEvent()} 
-each time an event occurs, receiving an {@link android.view.accessibility.AccessibilityEvent} object 
+<p>To observe all the events during a test, create an implementation of {@link
+android.app.UiAutomation.OnAccessibilityEventListener} and pass it to {@link
+android.app.UiAutomation#setOnAccessibilityEventListener setOnAccessibilityEventListener()}.
+Your listener interface then receives a call to {@link
+android.app.UiAutomation.OnAccessibilityEventListener#onAccessibilityEvent onAccessibilityEvent()}
+each time an event occurs, receiving an {@link android.view.accessibility.AccessibilityEvent} object
 that describes the event.</p>
 
-<p>There is a variety of other operations that the {@link android.app.UiAutomation} APIs expose 
-at a very low level to encourage the development of UI test tools such as <a href="{@docRoot}tools/help/uiautomator/index.html">uiautomator</a>. For instance, 
+<p>There is a variety of other operations that the {@link android.app.UiAutomation} APIs expose
+at a very low level to encourage the development of UI test tools such as <a href="{@docRoot}tools/help/uiautomator/index.html">uiautomator</a>. For instance,
 {@link android.app.UiAutomation} can also:</p>
 <ul>
   <li>Inject input events
@@ -1039,16 +1034,16 @@
   <li>Take screenshots
 </ul>
 
-<p>And most importantly for UI test tools, the {@link android.app.UiAutomation} APIs work 
+<p>And most importantly for UI test tools, the {@link android.app.UiAutomation} APIs work
 across application boundaries, unlike those in {@link android.app.Instrumentation}.</p>
 
 
 <h3 id="Systrace">Systrace events for apps</h3>
 
-<p>Android 4.3 adds the {@link android.os.Trace} class with two static methods, 
-{@link android.os.Trace#beginSection beginSection()} and {@link android.os.Trace#endSection()}, 
-which allow you to define blocks of code to include with the systrace report. By creating 
-sections of traceable code in your app, the systrace logs provide you a much more detailed 
+<p>Android 4.3 adds the {@link android.os.Trace} class with two static methods,
+{@link android.os.Trace#beginSection beginSection()} and {@link android.os.Trace#endSection()},
+which allow you to define blocks of code to include with the systrace report. By creating
+sections of traceable code in your app, the systrace logs provide you a much more detailed
 analysis of where slowdown occurs within your app.</p>
 
 <p>For information about using the Systrace tool, read <a href="{@docRoot}tools/debugging/systrace.html">Analyzing Display and Performance with Systrace</a>.</p>
@@ -1058,31 +1053,31 @@
 
 <h3 id="KeyStore">Android key store for app-private keys</h3>
 
-<p>Android now offers a custom Java Security Provider in the {@link java.security.KeyStore} 
-facility, called Android Key Store, which allows you to generate and save private keys that 
-may be seen and used by only your app. To load the Android Key Store, pass 
-{@code "AndroidKeyStore"} to {@link java.security.KeyStore#getInstance(String) 
+<p>Android now offers a custom Java Security Provider in the {@link java.security.KeyStore}
+facility, called Android Key Store, which allows you to generate and save private keys that
+may be seen and used by only your app. To load the Android Key Store, pass
+{@code "AndroidKeyStore"} to {@link java.security.KeyStore#getInstance(String)
 KeyStore.getInstance()}.</p>
 
-<p>To manage your app's private credentials in the Android Key Store, generate a new key with 
-{@link java.security.KeyPairGenerator} with {@link android.security.KeyPairGeneratorSpec}. First 
-get an instance of {@link java.security.KeyPairGenerator} by calling {@link 
-java.security.KeyPairGenerator#getInstance getInstance()}. Then call 
-{@link java.security.KeyPairGenerator#initialize initialize()}, passing it an instance of 
-{@link android.security.KeyPairGeneratorSpec}, which you can get using 
-{@link android.security.KeyPairGeneratorSpec.Builder KeyPairGeneratorSpec.Builder}. 
-Finally, get your {@link java.security.KeyPair} by calling {@link 
+<p>To manage your app's private credentials in the Android Key Store, generate a new key with
+{@link java.security.KeyPairGenerator} with {@link android.security.KeyPairGeneratorSpec}. First
+get an instance of {@link java.security.KeyPairGenerator} by calling {@link
+java.security.KeyPairGenerator#getInstance getInstance()}. Then call
+{@link java.security.KeyPairGenerator#initialize initialize()}, passing it an instance of
+{@link android.security.KeyPairGeneratorSpec}, which you can get using
+{@link android.security.KeyPairGeneratorSpec.Builder KeyPairGeneratorSpec.Builder}.
+Finally, get your {@link java.security.KeyPair} by calling {@link
 java.security.KeyPairGenerator#generateKeyPair generateKeyPair()}.</p>
 
 
 <h3 id="HardwareKeyChain">Hardware credential storage</h3>
 
-<p>Android also now supports hardware-backed storage for your {@link android.security.KeyChain} 
-credentials, providing more security by making the keys unavailable for extraction. That is, once 
-keys are in a hardware-backed key store (Secure Element, TPM, or TrustZone), they can be used for 
-cryptographic operations but the private key material cannot be exported. Even the OS kernel 
-cannot access this key material. While not all Android-powered devices support storage on 
-hardware, you can check at runtime if hardware-backed storage is available by calling 
+<p>Android also now supports hardware-backed storage for your {@link android.security.KeyChain}
+credentials, providing more security by making the keys unavailable for extraction. That is, once
+keys are in a hardware-backed key store (Secure Element, TPM, or TrustZone), they can be used for
+cryptographic operations but the private key material cannot be exported. Even the OS kernel
+cannot access this key material. While not all Android-powered devices support storage on
+hardware, you can check at runtime if hardware-backed storage is available by calling
 {@link android.security.KeyChain#isBoundKeyAlgorithm KeyChain.IsBoundKeyAlgorithm()}.</p>
 
 
@@ -1091,9 +1086,9 @@
 
 <h3 id="ManifestFeatures">Declarable required features</h3>
 
-<p>The following values are now supported in the <a 
+<p>The following values are now supported in the <a
 href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature>}</a>
-element so you can ensure that your app is installed only on devices that provide the features 
+element so you can ensure that your app is installed only on devices that provide the features
 your app needs.</p>
 
 <dl>
@@ -1137,8 +1132,8 @@
 
 
 <h3 id="ManifestPermissions">User permissions</h3>
-<p>The following values are now supported in the <a 
-href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code &lt;uses-permission>}</a> 
+<p>The following values are now supported in the <a
+href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code &lt;uses-permission>}</a>
 to declare the
 permissions your app requires in order to access certain APIs.</p>
 
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
index 88cdec4..7004b0a 100644
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ b/docs/html/distribute/googleplay/spotlight/index.jd
@@ -22,6 +22,35 @@
             margin-bottom:40px;
             margin-top:30px;">
    <div style="padding:0 0 0 29px;">
+        <h4>Developer Story: Colopl</h4>
+          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 17px 20px 9px 0;" 
+            src="//lh3.ggpht.com/sx2ILNaXQYOsHfR91T5tUWGlfXE1FutHCBN02Fll6mi9gIaG6RZCGbeJMtIvOoegCPTh=w124" >
+          <div style="width:700px;">
+          <p style="margin-top:26px;
+                    margin-bottom:12px;">
+          The creators of Kuma The Bear, Japan-based <a href="https://play.google.com/store/apps/developer?id=COLOPL,+Inc." target="_android">Colopl</a>, talk about how Google Play and Android allowed them to grow their business to become one of the most profitable games publishers in APAC to date. </p>
+           </div>
+           <iframe style="float:left;
+             margin-right:24px;
+             margin-top:14px;" width="700" height="394" src=
+             "http://www.youtube.com/embed/CbpoZeQCNe4?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
+           </iframe>
+   </div> 
+</div>
+
+<div style="background: #F0F0F0;
+            border-top: 1px solid #DDD;
+            padding: 0px 0 24px 0;
+            overflow: auto;
+            clear:both;
+            margin-bottom:40px;
+            margin-top:30px;">
+   <div style="padding:0 0 0 29px;">
         <h4>Developer Story: redBus.in</h4>
           <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
             -moz-border-radius: 5px;
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png b/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png
index 697fb7d..cc5b1af 100644
--- a/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png b/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png
index 735262f..2625edb 100644
--- a/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png b/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png
index cfb7952..9d91475 100644
--- a/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png b/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png
index 5bb815a..f54a8af 100644
--- a/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png b/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png
index 1be3b21..230bad4 100644
--- a/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png b/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png
index 7e8aff2..2401d20 100644
--- a/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png b/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png
index b5db82e..57b4c03 100644
--- a/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png
new file mode 100644
index 0000000..697fb7d
--- /dev/null
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png
new file mode 100644
index 0000000..735262f
--- /dev/null
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png
new file mode 100644
index 0000000..cfb7952
--- /dev/null
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png
new file mode 100644
index 0000000..5bb815a
--- /dev/null
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png
new file mode 100644
index 0000000..1be3b21
--- /dev/null
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png
new file mode 100644
index 0000000..7e8aff2
--- /dev/null
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png
new file mode 100644
index 0000000..b5db82e
--- /dev/null
+++ b/docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art.jd b/docs/html/distribute/promote/device-art.jd
index 58e183c..09a3941 100644
--- a/docs/html/distribute/promote/device-art.jd
+++ b/docs/html/distribute/promote/device-art.jd
@@ -173,12 +173,13 @@
       title: 'Nexus 7',
       url: 'http://www.google.com/nexus/7/',
       physicalSize: 7,
-      physicalHeight: 7.81,
-      density: '213dpi',
+      physicalHeight: 8,
+      actualResolution: [1200,1920],
+      density: 'XHDPI',
       landRes: ['shadow', 'back', 'fore'],
-      landOffset: [315,270],
+      landOffset: [326,245],
       portRes: ['shadow', 'back', 'fore'],
-      portOffset: [264,311],
+      portOffset: [244,326],
       portSize: [800,1280]
     },
     {
@@ -210,6 +211,20 @@
       archived: true
     },
     {
+      id: 'nexus_7_2012',
+      title: 'Nexus 7 (2012)',
+      url: 'http://www.google.com/nexus/7/',
+      physicalSize: 7,
+      physicalHeight: 7.81,
+      density: '213dpi',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [315,270],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [264,311],
+      portSize: [800,1280],
+      archived: true
+    },
+    {
       id: 'galaxy_nexus',
       title: 'Galaxy Nexus',
       url: 'http://www.android.com/devices/detail/galaxy-nexus',
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index d5b5bdf..15092a0 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -227,6 +227,12 @@
 <table>
   <tr><th>Platform Version</th><th>API Level</th><th>VERSION_CODE</th><th>Notes</th></tr>
 
+    <tr><td><a href="{@docRoot}about/versions/android-4.3.html">Android 4.3</a></td>
+    <td><a href="{@docRoot}sdk/api_diff/18/changes.html" title="Diff Report">18</a></td>
+    <td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}</td>
+    <td><a href="{@docRoot}about/versions/jelly-bean.html">Platform
+Highlights</a></td></tr>
+
     <tr><td><a href="{@docRoot}about/versions/android-4.2.html">Android 4.2, 4.2.2</a></td>
     <td><a href="{@docRoot}sdk/api_diff/17/changes.html" title="Diff Report">17</a></td>
     <td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}</td>
diff --git a/docs/html/images/video-Colopl.png b/docs/html/images/video-Colopl.png
new file mode 100644
index 0000000..0ee88c6
--- /dev/null
+++ b/docs/html/images/video-Colopl.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index a972309..d610899 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -20,6 +20,7 @@
         <a href="" class="slideshow-next">Next</a>
         <div class="frame">
             <ul>
+
                 <li class="item carousel-home">
                     <div class="content-left col-9">
                         <a href="{@docRoot}about/versions/jelly-bean.html"><img src="{@docRoot}images/home/android-jellybean.png" ></a>
@@ -34,41 +35,23 @@
                     <p><a href="{@docRoot}about/versions/jelly-bean.html" class="button">Learn More</a></p>
                     </div>
                 </li>
-                <li class="item carousel-home">
-                    <div class="content-left col-11" style="padding-top:10px;">
-                        <a href="{@docRoot}channels/io2013.html">
-                          <img src="{@docRoot}images/home/io-videos-2013.png" style="margin:60px 0 0;
-                          box-shadow: 3px 10px 18px 1px #999;">
-                        </a>
-                    </div>
-                    <div class="content-right col-4">
-                    <h1>Watch the Android talks from Google I/O</h1>
-                    <p>If you weren't able to attend Google I/O in person or couldn't make it
-                    to all the talks, you can catch up on the action
-                    with all the recordings, brought to you by
-                    <a href="http://developers.google.com/live">Google Developers Live</a>.</p>
-                    <p><a href="{@docRoot}channels/io2013.html" class="button"
-                    >See the Android talks</a></p>
-                    </div>
-                </li>
-
 
 
                 <li class="item carousel-home">
                     <div class="content-left col-11" style="padding-top:65px;">
                       <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
-                      <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:338px">
+                      <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px">
                         <div id="ytapiplayer">
-                          You need Flash player 8+ and JavaScript enabled to view this video.
+                          <a href="http://www.youtube.com/watch?v=CbpoZeQCNe4"><img width=600 src="{@docRoot}images/video-Colopl.png"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
                         </div>
                         <script type="text/javascript">
                             var params = { allowScriptAccess: "always" };
                             var atts = { id: "ytapiplayer" };
-                            swfobject.embedSWF("//www.youtube.com/v/O8i4HUw7JYA?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
-                              "ytapiplayer", "600", "338", "8", null, null, params, atts);
+                            swfobject.embedSWF("//www.youtube.com/v/CbpoZeQCNe4?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
+                              "ytapiplayer", "600", "336", "8", null, null, params, atts);
 
                             // Callback used to pause/resume carousel based on video state
-                            function onytplayerStateChange(newState) {              
+                            function onytplayerStateChange(newState) {
                                var isPaused = $("#pauseButton").hasClass("paused");
                                if ((newState == 1) || (newState == 3)) {
                                // if playing or buffering, pause the carousel
@@ -93,10 +76,31 @@
                       </div>
                     </div>
                     <div class="content-right col-4">
-                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />redBus.in</h1>
-                    <p>Bangalore-based developers redBus.in talk about how Android is helping them deliver a superior booking and travel experience to millions of daily bus riders in India.</p>
+                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Colopl</h1>
+                    <p>The creators of Kuma The Bear, Japan-based Colopl, talk about how Google Play and Android allowed them to grow their business to become one of the most profitable games publishers in APAC to date. </p>
                     </div>
                 </li>
+
+
+                <li class="item carousel-home">
+                    <div class="content-left col-11" style="padding-top:10px;">
+                        <a href="{@docRoot}channels/io2013.html">
+                          <img src="{@docRoot}images/home/io-videos-2013.png" style="margin:60px 0 0;
+                          box-shadow: 3px 10px 18px 1px #999;">
+                        </a>
+                    </div>
+                    <div class="content-right col-4">
+                    <h1>Watch the Android talks from Google I/O</h1>
+                    <p>If you weren't able to attend Google I/O in person or couldn't make it
+                    to all the talks, you can catch up on the action
+                    with all the recordings, brought to you by
+                    <a href="http://developers.google.com/live">Google Developers Live</a>.</p>
+                    <p><a href="{@docRoot}channels/io2013.html" class="button"
+                    >See the Android talks</a></p>
+                    </div>
+                </li>
+
+
                 <li class="item carousel-home">
                     <div class="content-left col-10">
                         <img src="{@docRoot}images/home/design.png" style="margin-top:30px">
@@ -108,6 +112,8 @@
                     <p><a href="{@docRoot}design/index.html" class="button">Learn More</a></p>
                     </div>
                 </li>
+
+
                 <li class="item carousel-home">
                         <div class="content-left col-10">
                             <img src="{@docRoot}images/home/google-play.png"
@@ -118,16 +124,16 @@
                         <p>The most visited store in the world for Android apps. Cloud-connected and always synced, it's never been easier for users to find and download your apps.</p>
 
                         <p><a href="{@docRoot}distribute/index.html" class="button">Learn More</a></p>
-                        </div> 
+                        </div>
                 </li>
             </ul>
         </div>
     </div>
     <!-- /End slideshow -->
-    
+
     <a href="" id="pauseButton" style="display:none">pause</a>
-    
-    
+
+
 </div>
 <div class="wrap" style="padding-bottom:20px">
     <!-- Section links -->
@@ -141,4 +147,4 @@
         </ul>
     </div>
     <!-- /Section links -->
-</div>     
+</div>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 0d0f348..aa3b2ec 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,43 +5,43 @@
 page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
 
 
-sdk.linux32_bundle_download=adt-bundle-linux-x86-20130522.zip
-sdk.linux32_bundle_bytes=439988972
-sdk.linux32_bundle_checksum=1fdd8d7537ab9217d61d32ab912f0243
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20130717.zip
+sdk.linux32_bundle_bytes=440035305
+sdk.linux32_bundle_checksum=ecfacb91df1ee63cce1edd4f1a5cda5a
 
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130522.zip
-sdk.linux64_bundle_bytes=440275051
-sdk.linux64_bundle_checksum=e38751ff372a8d6208fcef5659133e98
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130717.zip
+sdk.linux64_bundle_bytes=440322117
+sdk.linux64_bundle_checksum=ab177a06784340b8f1d136651e3dc62a
 
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130522.zip
-sdk.mac64_bundle_bytes=409047751
-sdk.mac64_bundle_checksum=3f4d05206d66e402e87b27a6b3dcf0f9
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130717.zip
+sdk.mac64_bundle_bytes=411609229
+sdk.mac64_bundle_checksum=07c891212a49b5f8495ea9d8d47ba3fe
 
-sdk.win32_bundle_download=adt-bundle-windows-x86-20130522.zip
-sdk.win32_bundle_bytes=446736316
-sdk.win32_bundle_checksum=53345fa4121fa58cc048f66c3af3bae9
+sdk.win32_bundle_download=adt-bundle-windows-x86-20130717.zip
+sdk.win32_bundle_bytes=446783216
+sdk.win32_bundle_checksum=0dd91095999d3539ca1ec4033d83d935
 
-sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130522.zip
-sdk.win64_bundle_bytes=446864400
-sdk.win64_bundle_checksum=b28817f62e7f54e3c683841b61b65564
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130717.zip
+sdk.win64_bundle_bytes=446911629
+sdk.win64_bundle_checksum=61ec74995b39166db7f079017a028cec
 
 
 
-sdk.linux_download=android-sdk_r22.0.1-linux.tgz
-sdk.linux_bytes=105617062
-sdk.linux_checksum=56ed27d456b4f0e0d3090b24f9b06757
+sdk.linux_download=android-sdk_r22.0.4-linux.tgz
+sdk.linux_bytes=105640988
+sdk.linux_checksum=4a5db98a58c68c24e66f04f07ac77da5
 
-sdk.mac_download=android-sdk_r22.0.1-macosx.zip
-sdk.mac_bytes=77206237
-sdk.mac_checksum=5c20497d7f7b9d28ee30e57cbf769c8c
+sdk.mac_download=android-sdk_r22.0.4-macosx.zip
+sdk.mac_bytes=77225662
+sdk.mac_checksum=384752505f4f2ba3627bd6aad0697f11
 
-sdk.win_download=android-sdk_r22.0.1-windows.zip
-sdk.win_bytes=113483496
-sdk.win_checksum=cb7f7703450afa5914fb4b8b8332a9f3
+sdk.win_download=android-sdk_r22.0.4-windows.zip
+sdk.win_bytes=113507679
+sdk.win_checksum=320b11d1ed85fd3f5e937697c333d895
 
-sdk.win_installer=installer_r22.0.1-windows.exe
-sdk.win_installer_bytes=93479015
-sdk.win_installer_checksum=81621d3b164f81f91e066011b325f88f
+sdk.win_installer=installer_r22.0.4-windows.exe
+sdk.win_installer_bytes=93502726
+sdk.win_installer_checksum=96a8ae367d84ed219e1eb2cf473667d0
 
 
 
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index b8ab24b..2a09636 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
 page.title=Installing the Eclipse Plugin
-adt.zip.version=22.0.1
-adt.zip.download=ADT-22.0.1.zip
-adt.zip.bytes=16815544
-adt.zip.checksum=64473af058fa8f02e36241ee378b3ac0
+adt.zip.version=22.0.4
+adt.zip.download=ADT-22.0.4.zip
+adt.zip.bytes=16838756
+adt.zip.checksum=f0291f4bb9d78ec34a7751cd2402cc2a
 
 @jd:body
 
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index 31cec0e..820edbd 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -29,25 +29,46 @@
 version.</p>
 
 <p>To determine what revision of an Android platform you have installed, refer to the
-<strong>Installed Packages</strong> listing in the Android SDK Manager.</p>
+<strong>Installed Packages</strong> listing in the Android
+<a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</p>
+
+<p class="caution"><strong>Important:</strong> To download the most recent Android
+system components from the Android SDK Manager, you must first update the SDK Tools to
+revision 22 or later and restart the SDK Manager. If you do not,
+the latest Android system components will not be available for download.</p>
 
 
 
+<h2 id="4.3">Android 4.3</h2>
 
 
-
-<h2 id="4.2">Android 4.2</h2>
-
-
-<p class="caution"><strong>Important:</strong> To download the new Android
-4.2.x system components from the Android SDK Manager, you must first update the
-SDK tools to revision 20 or later and restart the Android SDK Manager. If you do not,
-the Android 4.2 system components will not be available for download.</p>
-
 <div class="toggle-content opened">
 
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />Revision 1</a> <em>(July 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Initial release. The system version is 4.3.</p>
+    <dl>
+      <dt>Dependencies:</dt>
+      <dd>Android SDK Platform-tools r18 or higher is required.</dd>
+      <dd>Android SDK Tools 22.0.4 or higher is recommended.</dd>
+    </dl>
+
+  </div>
+</div>
+
+
+<h2 id="4.2">Android 4.2</h2>
+
+
+<div class="toggle-content closed">
+
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png"
 class="toggle-content-img" alt="" />Revision 2</a> <em>(February 2013)</em>
   </p>
 
@@ -150,12 +171,6 @@
 <h2 id="4.1">Android 4.1</h2>
 
 
-<p class="caution"><strong>Important:</strong> To download the new Android
-4.1.x system components from the Android SDK Manager, you must first update the
-SDK tools to revision 20 or later and restart the Android SDK Manager. If you do not,
-the Android 4.1 system components will not be available for download.</p>
-
-
 <div class="toggle-content closed">
 
   <p><a href="#" onclick="return toggleContent(this)">
@@ -269,11 +284,6 @@
 <h2 id="4.0.3">Android 4.0.3</h2>
 
 
-<p class="caution"><strong>Important:</strong> To download the new Android
-4.0.x system components from the Android SDK Manager, you must first update the
-SDK tools to revision 14 or later and restart the Android SDK Manager. If you do not,
-the Android 4.0.x system components will not be available for download.</p>
-
 <div class="toggle-content closed">
 
   <p><a href="#" onclick="return toggleContent(this)">
@@ -711,13 +721,6 @@
 <h2 id="2.3.4">Android 2.3.4</h2>
 
 
-
-<p>The sections below provide notes about successive releases of
-the Android 2.3.4 platform component for the Android SDK, as denoted by
-revision number. To determine what revision(s) of the Android
-2.3.4 platforms are installed in your SDK environment, refer to
-the "Installed Packages" listing in the Android SDK and AVD Manager.</p>
-
 <div class="toggle-content closed" >
 
 <p><a href="#" onclick="return toggleContent(this)">
@@ -865,14 +868,6 @@
 <h2 id="2.3">Android 2.3</h2>
 
 
-
-<p>The sections below provide notes about successive releases of
-the Android 2.3 platform component for the Android SDK, as denoted by
-revision number. To determine what revision(s) of the Android
-2.3 platforms are installed in your SDK environment, refer to
-the "Installed Packages" listing in the Android SDK and AVD Manager.</p>
-
-
 <div class="toggle-content closed" >
 
 <p><a href="#" onclick="return toggleContent(this)">
@@ -1033,4 +1028,4 @@
   <li>
     WVGA854 (480x854 high density, normal screen)
   </li>
-</ul>
\ No newline at end of file
+</ul>
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 52647ff..7b0b5a8 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -53,9 +53,46 @@
 <p>For a summary of all known issues in ADT, see <a
 href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
 
+
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 22.0.4</a> <em>(July 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 1.6 or higher is required for ADT 22.0.4.</li>
+      <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 22.0.4.</li>
+      <li>ADT 22.0.4 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
+      Tools r22.0.4</a>. If you haven't already installed SDK Tools r22.0.4 into your SDK, use the
+      Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+      <li>Fixed problem with compiling Renderscript code.</li>
+      <li>Improved Gradle export with better workflow and error reporting.</li>
+      <li>Improved Gradle multi-module export feature.</li>
+      <li>Updated build logic to force exporting of the classpath containers unless you are using
+        the Maven plugin.</li>
+    </ul>
+  </dd>
+
+</dl>
+</div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 22.0.1</a> <em>(May 2013)</em>
   </p>
 
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index 74caaf4..1f34987 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -1,29 +1,29 @@
 ndk=true
 page.template=sdk
 
-ndk.mac64_download=android-ndk-r8e-darwin-x86_64.tar.bz2
-ndk.mac64_bytes=508419298
-ndk.mac64_checksum=efac96fab20e6ddb1311d6ba5648ce72
+ndk.mac64_download=android-ndk-r9-darwin-x86_64.tar.bz2
+ndk.mac64_bytes=726430529
+ndk.mac64_checksum=b975271d8f064611e7e12bf87b736826
 
-ndk.mac32_download=android-ndk-r8e-darwin-x86.tar.bz2
-ndk.mac32_bytes=496238878
-ndk.mac32_checksum=e17e707464c45c0d5615e4d0ae6a5cf7
+ndk.mac32_download=android-ndk-r9-darwin-x86.tar.bz2
+ndk.mac32_bytes=710781553
+ndk.mac32_checksum=6f7c4dd38df9079bb4b13846add5c0da
 
-ndk.linux64_download=android-ndk-r8e-linux-x86_64.tar.bz2
-ndk.linux64_bytes=466853553
-ndk.linux64_checksum=fa812352956067e7a9eefc0274675e9a
+ndk.linux64_download=android-ndk-r9-linux-x86_64.tar.bz2
+ndk.linux64_bytes=669064468
+ndk.linux64_checksum=3eedc86b20ec09fcd1fd03f4481a706d
 
-ndk.linux32_download=android-ndk-r8e-linux-x86.tar.bz2
-ndk.linux32_bytes=461526099
-ndk.linux32_checksum=26d774b0884bcd98de08eb4de41ab532
+ndk.linux32_download=android-ndk-r9-linux-x86.tar.bz2
+ndk.linux32_bytes=660787157
+ndk.linux32_checksum=999d155ba772c49baacee6d41d664922
 
-ndk.win64_download=android-ndk-r8e-windows-x86_64.zip
-ndk.win64_bytes=461298980
-ndk.win64_checksum=11eb99b3b56fc86d9d231ebff5c41db3
+ndk.win64_download=android-ndk-r9-windows-x86_64.zip
+ndk.win64_bytes=826661995
+ndk.win64_checksum=cd56cc1036235f16369f2112fa27be91
 
-ndk.win32_download=android-ndk-r8e-windows-x86.zip
-ndk.win32_bytes=434701805
-ndk.win32_checksum=fb41ed2bff5610b14a7b6f085ab86213
+ndk.win32_download=android-ndk-r9-windows-x86.zip
+ndk.win32_bytes=777938252
+ndk.win32_checksum=9c1f66ff963cc61e338964c5f97a4d34
 
 page.title=Android NDK
 @jd:body
@@ -255,13 +255,286 @@
 
 <h2 id="Revisions">Revisions</h2>
 
-<p>The sections below provide information and notes about successive releases of
-the NDK, as denoted by revision number. </p>
-
+<p>The following sections provide information about releases of the NDK.</p>
 
 <div class="toggle-content opened">
+  <p>
+    <a href="#" onclick="return toggleContent(this)"> <img
+      src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
+    >Android NDK, Revision 9</a> <em>(July 2013)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <dl>
+      <dt>Important changes:</dt>
+      <dd>
+        <ul>
+          <li>Added support for Android 4.3 (API level 18). For more information, see
+            {@code STABLE-APIS.html} and new code examples in {@code samples/gles3jni/README}.
+          <li>Added headers and libraries for OpenGL ES 3.0, which is supported by Android 4.3
+            (API level 18) and higher.</li>
+          <li>Added GNU Compiler Collection (GCC) 4.8 compiler to the NDK. Since GCC 4.6 is still
+            the default, you must explicitly enable this option:
+            <ul>
+              <li>For {@code ndk-build} builds, export {@code NDK_TOOLCHAIN_VERSION=4.8} or
+                add it in {@code Application.mk}.</li>
+              <li>For standalone builds, use the {@code --toolchain=} option in
+                {@code make-standalone-toolchain.sh}, for example:<br>
+                {@code --toolchain=arm-linux-androideabi-4.8}</li>
+            </ul>
+            <p class="note"><strong>Note:</strong>
+            The {@code -Wunused-local-typedefs} option is enabled by {@code -Wall}. Be
+            sure to add {@code __attribute__((unused))} if you use compile-time asserts like
+            {@code sources/cxx-stl/stlport/stlport/stl/config/features.h}, line #311. For more
+            information, see
+            <a href="https://android-review.googlesource.com/#/c/55460">Change 55460</a></p>
+            <p class="note"><strong>Note:</strong>
+            In the GCC 4.7 release and later, ARM compilers generate unaligned access code by
+            default for ARMv6 and higher build targets. You may need to add the
+            {@code -mno-unaligned-access} build option when building for kernels that do not support
+            this feature.</p>
+          </li>
+          <li>Added Clang 3.3 support. The {@code NDK_TOOLCHAIN_VERSION=clang} build option
+            now picks Clang 3.3 by default.
+            <p class="note"><strong>Note:</strong>
+             Both GCC 4.4.3 and Clang 3.1 are deprecated, and will be removed from the next NDK
+             release.</p></li>
+          <li>Updated GNU Project Debugger (GDB) to support python 2.7.5.</li>
+          <li>Added MCLinker to support Windows hosts. Since {@code ld.gold}
+            is the default where available, you must add {@code -fuse-ld=mcld} in
+            {@code LOCAL_LDFLAGS} or {@code APP_LDFLAGS} to enable MCLinker.</li>
+          <li>Added {@code ndk-depends} tool which prints ELF library dependencies.
+            For more information, see {@code NDK-DEPENDS.html}.
+            (<a href="http://b.android.com/53486">Issue 53486</a>)</li>
+        </ul>
+      </dd>
+
+      <dt>Important bug fixes:</dt>
+      <dd>
+        <ul>
+          <li>Fixed potential event handling issue in {@code android_native_app_glue}.
+            (<a href="http://b.android.com/41755">Issue 41755</a>)</li>
+          <li>Fixed ARM/GCC-4.7 build to generate sufficient alignment for NEON load and store
+            instructions VST and VLD.
+            (<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57271">GCC Issue 57271</a>)</li>
+          <li>Fixed a GCC 4.4.3/4.6/4.7 internal compiler error (ICE) for a constant negative index
+            value on a string literal.
+            (<a href="http://b.android.com/54623">Issue 54623</a>)</li>
+          <li>Fixed GCC 4.7 segmentation fault for constant initialization with an object address.
+            (<a href="http://b.android.com/56508">Issue 56508</a>)</li>
+          <li>Fixed GCC 4.6 ARM segmentation fault for <code>-O</code> values when using Boost
+            1.52.0. (<a href="http://b.android.com/42891">Issue 42891</a>)
+          <li>Fixed {@code libc.so} and {@code libc.a} to support the {@code wait4()} function.
+            (<a href="http://b.android.com/19854">Issue 19854</a>)</li>
+          <li>Updated the x86 libc.so and libc.a files to include the {@code clone()}
+            function.</li>
+          <li>Fixed {@code LOCAL_SHORT_COMMANDS} bug where the {@code linker.list} file is
+            empty or not used.</li>
+          <li>Fixed GCC MIPS build on Mac OS to use CFI directives, without which
+            {@code ld.mcld --eh-frame-hdr} fails frequently.</li>
+          <li>Fixed Clang 3.2 X86/MIPS internal compiler error in {@code llvm/lib/VMCore/Value.cpp}.
+            (<a href="https://android-review.googlesource.com/#/c/59021">Change 59021</a>)</li>
+          <li>Fixed GCC 4.7 64-bit Windows assembler crash. (Error: {@code out of memory allocating
+            4294967280 bytes}).</li>
+          <li>Updated {@code ndk-gdb} script so that the {@code --start} or {@code --launch} actions
+            now wait for the GNU Debug Server, so that it can more reliably hit breakpoints set
+            early in the execution path (such as breakpoints in JNI code).
+            (<a href="http://b.android.com/41278">Issue 41278</a>)
+            <p class="note"><strong>Note:</strong>
+              This feature requires jdb and produces warning about pending breakpoints.
+              Specify the {@code --nowait} option to restore previous behavior.
+            </p>
+          </li>
+          <li>Fixed GDB crash when library list is empty.</li>
+          <li>Fixed GDB crash when using a {@code stepi} command past a {@code bx pc} or
+            {@code blx pc} Thumb instruction.
+            (<a href="http://b.android.com/56962">Issue 56962</a>,
+             <a href="http://b.android.com/36149">Issue 36149</a>)</li>
+          <li>Fixed MIPS {@code gdbserver} to look for {@code DT_MIPS_RLD_MAP} instead of
+            {@code DT_DEBUG}. (<a href="http://b.android.com/56586">Issue 56586</a>)</li>
+          <li>Fixed a circular dependency in the ndk-build script, for example: If A-&gt;B and
+            B-&gt;B, then B was dropped from build.
+            (<a href="http://b.android.com/56690">Issue 56690</a>)</li>
+        </ul>
+      </dd>
+
+      <dt>Other bug fixes:</dt>
+      <dd>
+        <ul>
+          <li>Fixed the {@code ndk-build} script to enable you to specify a version of Clang as a
+            command line option (e.g., {@code NDK_TOOLCHAIN_VERSION=clang3.2}). Previously, only
+            specifying the version as an environment variable worked.</li>
+          <li>Fixed gabi++ size of {@code _Unwind_Exception} to be 24 for MIPS build targets when
+            using the Clang compiler.
+            (<a href="https://android-review.googlesource.com/#/c/54141">Change 54141</a>)</li>
+          <li>Fixed the {@code ndk-build} script to ensure that built libraries are actually
+            removed from projects that include prebuilt static libraries when using the
+            {@code ndk-build clean} command.
+            (<a href="https://android-review.googlesource.com/#/c/54461">Change 54461</a>,
+             <a href="https://android-review.googlesource.com/#/c/54480">Change 54480</a>)</li>
+          <li>Modified the {@code NDK_ANALYZE=1} option to be less verbose.</li>
+          <li>Fixed {@code gnu-libstdc++/Android.mk} to include a {@code backward/} path for builds
+            that use backward compability.
+            (<a href="http://b.android.com/53404">Issue 53404</a>)</li>
+          <li>Fixed a problem where {@code stlport new} sometimes returned random values.</li>
+          <li>Fixed {@code ndk-gdb} to match the order of {@code CPU_ABIS}, not {@code APP_ABIS}.
+            (<a href="http://b.android.com/54033">Issue 54033</a>)</li>
+          <li>Fixed a problem where the NDK 64-bit build on MacOSX choses the wrong path for
+            compiler.
+            (<a href="http://b.android.com/53769">Issue 53769</a>)</li>
+          <li>Fixed build scripts to detect 64-bit Windows Vista.
+            (<a href="http://b.android.com/54485">Issue 54485</a>)</li>
+          <li>Fixed x86 {@code ntonl/swap32} error: {@code invalid 'asm': operand number
+            out of range}.
+            (<a href="http://b.android.com/54465">Issue 54465</a>,
+             <a href="https://android-review.googlesource.com/#/c/57242">Change 57242</a>)</li>
+          <li>Fixed {@code ld.gold} to merge string literals.</li>
+          <li>Fixed {@code ld.gold} to handle large symbol alignment.</li>
+          <li>Updated {@code ld.gold} to enable the {@code --sort-section=name} option.</li>
+          <li>Fixed GCC 4.4.3/4.6/4.7 to suppress the {@code -export-dynamic} option for
+            statically linked programs. GCC no longer adds an {@code .interp} section for statically
+            linked programs.</li>
+          <li>Fixed GCC 4.4.3 {@code stlport} compilation error about inconsistent {@code typedef}
+            of {@code _Unwind_Control_Block}.
+            (<a href="http://b.android.com/54426">Issue 54426</a>)</li>
+          <li>Fixed {@code awk} scripts to handle {@code AndroidManifest.xml} files created on
+            Windows which may contain trailing {@code \r} characters and cause build errors.
+            (<a href="http://b.android.com/42548">Issue 42548</a>)</li>
+          <li>Fixed {@code make-standalone-toolchain.sh} to probe the {@code prebuilts/}
+            directory to detect if the host is 32 bit or 64 bit.</li>
+          <li>Fixed the Clang 3.2 {@code -integrated-as} option.</li>
+          <li>Fixed the Clang 3.2 ARM EHABI compact model {@code pr1} and {@code pr2} handler data.
+            </li>
+          <li>Added clang {@code -mllvm -arm-enable-ehabi} option to fix the following clang error:
+            <pre>clang: for the -arm-enable-ehabi option: may only occur zero or one times!</pre>
+            </li>
+          <li>Fixed build failure when there is no {@code uses-sdk} element in application
+            manifest. (<a href="http://b.android.com/57015">Issue 57015</a>)</li>
+        </ul>
+
+      </dd>
+      <dt>Other changes:</dt>
+      <dd>
+        <ul>
+          <li>Header Fixes
+            <ul>
+              <li>Modified headers to make {@code __set_errno} an inlined function, since
+                {@code __set_errno} in {@code errno.h} is deprecated, and {@code libc.so} no longer
+                exports it.</li>
+              <li>Modified {@code elf.h} to include {@code stdint.h}.
+                (<a href="http://b.android.com/55443">Issue 55443</a>)</li>
+              <li>Fixed {@code sys/un.h} to be included independently of other headers.
+                (<a href="http://b.android.com/53646">Issue 53646</a>)</li>
+              <li>Fixed all of the {@code MotionEvent_getHistorical} API family to take the
+                {@code const AInputEvent* motion_event}.
+                (<a href="http://b.android.com/55873">Issue 55873</a>)</li>
+              <li>Fixed {@code malloc_usable_size} to take {@code const void*}.
+                (<a href="http://b.android.com/55725">Issue 55725</a>)</li>
+              <li>Fixed stdint.h to be more compatible with C99.
+                (<a href="https://android-review.googlesource.com/#/c/46821">Change 46821</a>)</li>
+              <li>Modified {@code wchar.h} to not redefine {@code WCHAR_MAX} and
+                {@code WCHAR_MIN}</li>
+              <li>Fixed {@code &lt;inttypes.h&gt;} declaration for pointer-related {@code PRI} and
+                {@code SCN} macros. (<a href="http://b.android.com/57218">Issue 57218</a>)</li>
+              <li>Changed the {@code sys/cdefs.h} header so that {@code __WCHAR_TYPE__} is 32-bit
+                for API levels less than 9, which means that {@code wchat_t} is 32-bit for all
+                API levels. To restore the previous behavior, define the {@code _WCHAR_IS_8BIT}
+                boolean variable. (<a href="http://b.android.com/57267">Issue 57267</a>)</li>
+            </ul>
+          </li>
+          <li>Added more formatting in NDK {@code docs/} and miscellaneous documentation fixes.
+            </li>
+          <li>Added support for a thin archive technique when building static libraries.
+            (<a href="http://b.android.com/40303">Issue 40303</a>)</li>
+          <li>Updated script {@code make-standalone-toolchain.sh} to support the {@code stlport}
+            library in addition to {@code gnustl}, when you specify the option
+            {@code --stl=stlport}. For more information, see {@code STANDALONE-TOOLCHAIN.html}.</li>
+          <li>Updated the {@code make-standalone-toolchain.sh} script so that the
+            {@code --llvm-version=} option creates the {@code $TOOLCHAIN_PREFIX-clang} and
+            {@code $TOOLCHAIN_PREFIX-clang++} scripts in addition to {@code clang} and
+            {@code clang++}, to avoid using the host's clang and clang++ definitions by accident.
+            </li>
+          <li>Added two flags to re-enable two optimizations in upstream Clang but disabled in
+              NDK for better compatibility with code compiled by GCC:
+            <ul>
+              <li>Added a {@code -fcxx-missing-return-semantics} flag to re-enable <em>missing return
+                semantics</em> in Clang 3.2+. Normally, all paths should terminate with a return
+                statement for a value-returning function. If this is not the case, clang inserts
+                an undefined instruction (or trap in debug mode) at the path without a return
+                statement. If you are sure your code is correct, use this flag to allow the
+                optimizer to take advantage of the undefined behavior. If you are not sure, do not
+                use this flag. The caller may still receive a random incorrect value, but the
+                optimizer will not exploit it and make your code harder to debug.</li>
+              <li>Added a {@code -fglobal-ctor-const-promotion} flag to re-enable
+                promoting global variables with static constructor to be constants. With this flag,
+                the global variable optimization pass of LLVM tries to evaluate the global
+                variables with static constructors and promote them to global constants. Although
+                this optimization is correct, it may cause some incompatability with code compiled
+                by GCC. For example, code may do {@code const_cast} to cast the constant to mutable
+                and modify it. In GCC, the variable is in read-write and the code is run by
+                accident. In Clang, the const variable is in read-only memory and may cause your
+                application to crash.</li>
+            </ul>
+          </li>
+          <li>Added {@code -mldc1-sdc1} to the MIPS GCC and Clang compilers. By default, compilers
+            align 8-byte objects properly and emit the {@code ldc1} and {@code sdc1} instructions
+            to move them around. If your app uses a custom allocator that does not always align
+            with a new object's 8-byte boundary in the same way as the default allocator, your app
+            may crash due to {@code ldc1} and {@code sdc1} operations on unaligned memory. In this
+            case, use the {@code -mno-ldc1-sdc1} flag to workaround the problem.</li>
+          <li>Downgraded the event severity from warning to info if {@code APP_PLATFORM_LEVEL} is
+            larger than {@code APP_MIN_PLATFORM_LEVEL}. The {@code APP_PLATFORM_LEVEL} may be lower
+            than {@code APP_PLATFORM} in {@code jni/Application.mk} because the NDK does not have
+            headers for all levels. In this case, the actual level is shifted downwards. The
+            {@code APP_MIN_PLATFORM_LEVEL} is specified by the {@code android:minSdkVersion} in
+            your application's manifest.
+            (<a href="http://b.android.com/39752">Issue 39752</a>)</li>
+          <li>Added the {@code android_getCpuIdArm()} and {@code android_setCpuArm()} methods to
+            {@code cpu-features.c}. This addition enables easier retrieval of the ARM CPUID
+            information. (<a href="http://b.android.com/53689">Issue 53689</a>)</li>
+          <li>Modified {@code ndk-build} to use GCC 4.7's {@code as/ld} for Clang compiling.
+            <p class="note"><strong>Note:</strong>
+              In GCC 4.7, {@code monotonic_clock} and {@code is_monotonic} have been renamed to
+              {@code steady_clock} and {@code is_steady}, respectively.</p></li>
+          <li>Added the following new warnings to the {@code ndk-build} script:
+            <ul>
+              <li>Added warnings if {@code LOCAL_LDLIBS/LDFLAGS} are used in static library
+                modules.</li>
+              <li>Added a warning if a configuration has no module to build.</li>
+              <li>Added a warning for non-system libraries being used in
+                {@code LOCAL_LDLIBS/LDFLAGS} of a shared library or executable modules.</li>
+            </ul>
+          </li>
+          <li>Updated build scripts, so that if {@code APP_MODULES} is not defined and only static
+            libraries are listed in {@code Android.mk}, the script force-builds all of them.
+            (<a href="http://b.android.com/53502">Issue 53502</a>)</li>
+          <li>Updated {@code ndk-build} to support absolute paths in {@code LOCAL_SRC_FILES}.</li>
+          <li>Removed the {@code *-gdbtui} executables, which are duplicates of the {@code *-gdb}
+            executables with the {@code -tui} option enabled.</li>
+          <li>Updated the build scripts to warn you when the Edison Design Group (EDG) compiler
+            front-end turns {@code _STLP_HAS_INCLUDE_NEXT} back on.
+            (<a href="http://b.android.com/53646">Issue 53646</a>)</li>
+          <li>Added the environment variable {@code NDK_LIBS_OUT} to allow overriding of the
+            path for {@code libraries/gdbserver} from the default {@code $PROJECT/libs}.
+            For more information, see {@code OVERVIEW.html}.</li>
+          <li>Changed ndk-build script defaults to compile code with format string protection
+            {@code -Wformat -Werror=format-security}. You may set
+            {@code LOCAL_DISABLE_FORMAT_STRING_CHECKS=true} to disable it.
+            For more information, see {@code ANDROID-MK.html}</li>
+          <li>Added STL pretty-print support in {@code ndk-gdb-py}. For more information, see
+            {@code NDK-GDB.html}.</li>
+          <li>Added tests based on the googletest frameworks.</li>
+          <li>Added a notification to the toolchain build script that warns you if the current shell
+            is not {@code bash}.</li>
+        </ul>
+      </dd>
+    </dl>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
   <p><a href="#" onclick="return toggleContent(this)">
-    <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt="">Android NDK, Revision 8e</a> <em>(March 2013)</em>
   </p>
 
@@ -283,7 +556,7 @@
             build automatically sorts out the order of libraries specified in
             {@code LOCAL_STATIC_LIBRARIES}, {@code LOCAL_WHOLE_STATIC_LIBRARIES} and
             {@code LOCAL_SHARED_LIBRARIES}. For more information, see {@code CHANGES.HTML}.
-            (<a href="http://code.google.com/p/android/issues/detail?id=39378">Issue 39378</a>)</li>
+            (<a href="http://b.android.com/39378">Issue 39378</a>)</li>
         </ul>
       </dd>
 
@@ -295,23 +568,23 @@
           <li>Fixed build script which unconditionally builds Clang/llvm for MacOSX in 64-bit.</li>
           <li>Fixed GCC 4.6/4.7 internal compiler error:
             {@code gen_thumb_movhi_clobber at config/arm/arm.md:5832}.
-            (<a href="http://code.google.com/p/android/issues/detail?id=52732">Issue 52732</a>)</li>
+            (<a href="http://b.android.com/52732">Issue 52732</a>)</li>
           <li>Fixed build problem where GCC/ARM 4.6/4.7 fails to link code using 64-bit atomic
             built-in functions.
-            (<a href="http://code.google.com/p/android/issues/detail?id=41297">Issue 41297</a>)</li>
+            (<a href="http://b.android.com/41297">Issue 41297</a>)</li>
           <li>Fixed GCC 4.7 linker DIV usage mismatch errors.
           (<a href="http://sourceware.org/ml/binutils/2012-12/msg00202.html">Sourceware Issue</a>)
           <li>Fixed GCC 4.7 internal compiler error {@code build_data_member_initialization, at
             cp/semantics.c:5790}.</li>
           <li>Fixed GCC 4.7 internal compiler error {@code redirect_eh_edge_1, at tree-eh.c:2214}.
-            (<a href="http://code.google.com/p/android/issues/detail?id=52909">Issue 52909</a>)</li>
+            (<a href="http://b.android.com/52909">Issue 52909</a>)</li>
           <li>Fixed a GCC 4.7 segfault.
             (<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55245">GCC Issue</a>)</li>
           <li>Fixed {@code &lt;chrono&gt;} clock resolution and enabled {@code steady_clock}.
-            (<a href="http://code.google.com/p/android/issues/detail?id=39680">Issue 39680</a>)</li>
+            (<a href="http://b.android.com/39680">Issue 39680</a>)</li>
           <li>Fixed toolchain to enable {@code _GLIBCXX_HAS_GTHREADS} for GCC 4.7 libstdc++.
-            (<a href="http://code.google.com/p/android/issues/detail?id=41770">Issue 41770</a>,
-             <a href="http://code.google.com/p/android/issues/detail?id=41859">Issue 41859</a>)</li>
+            (<a href="http://b.android.com/41770">Issue 41770</a>,
+             <a href="http://b.android.com/41859">Issue 41859</a>)</li>
           <li>Fixed problem with the X86 MXX/SSE code failing to link due to missing
             {@code posix_memalign}.
             (<a href="https://android-review.googlesource.com/#/c/51872">Change 51872</a>)</li>
@@ -321,24 +594,24 @@
           <li>Fixed GCC4.7/X86 to restore earlier {@code cmov} behavior.
             (<a href="http://gcc.gnu.org/viewcvs?view=revision&revision=193554">GCC Issue</a>)</li>
           <li>Fixed handling NULL return value of {@code setlocale()} in libstdc++/GCC4.7.
-            (<a href="http://code.google.com/p/android/issues/detail?id=46718">Issue 46718</a>)
+            (<a href="http://b.android.com/46718">Issue 46718</a>)
           <li>Fixed {@code ld.gold} runtime undefined reference to {@code __exidx_start} and
             {@code __exidx_start_end}.
             (<a href="https://android-review.googlesource.com/#/c/52134">Change 52134</a>)</li>
           <li>Fixed Clang 3.1 internal compiler error when using Eigen library.
-            (<a href="http://code.google.com/p/android/issues/detail?id=41246">Issue 41246</a>)</li>
+            (<a href="http://b.android.com/41246">Issue 41246</a>)</li>
           <li>Fixed Clang 3.1 internal compiler error including {@code &lt;chrono&gt;} in C++11 mode.
-            (<a href="http://code.google.com/p/android/issues/detail?id=39600">Issue 39600</a>)</li>
+            (<a href="http://b.android.com/39600">Issue 39600</a>)</li>
           <li>Fixed Clang 3.1 internal compiler error when generating object code for a method
             call to a uniform initialized {@code rvalue}.
-            (<a href="http://code.google.com/p/android/issues/detail?id=41387">Issue 41387</a>)</li>
+            (<a href="http://b.android.com/41387">Issue 41387</a>)</li>
           <li>Fixed Clang 3.1/X86 stack realignment.
             (<a href="https://android-review.googlesource.com/#/c/52154">Change 52154</a>)</li>
           <li>Fixed problem with GNU Debugger (GDB) SIGILL when debugging on Android 4.1.2.
-            (<a href="http://code.google.com/p/android/issues/detail?id=40941">Issue 40941</a>)</li>
+            (<a href="http://b.android.com/40941">Issue 40941</a>)</li>
           <li>Fixed problem where GDB cannot set {@code source:line} breakpoints when symbols contain
             long, indirect file paths.
-            (<a href="http://code.google.com/p/android/issues/detail?id=42448">Issue 42448</a>)</li>
+            (<a href="http://b.android.com/42448">Issue 42448</a>)</li>
           <li>Fixed GDB {@code read_program_header} for MIPS PIE executables.
             (<a href="https://android-review.googlesource.com/#/c/49592">Change 49592</a>)</li>
           <li>Fixed {@code STLport} segmentation fault in {@code uncaught_exception()}.
@@ -346,7 +619,7 @@
           <li>Fixed {@code STLport} bus error in exception handling due to unaligned access of
             {@code DW_EH_PE_udata2}, {@code DW_EH_PE_udata4}, and {@code DW_EH_PE_udata8}.</li>
           <li>Fixed Gabi++ infinite recursion problem with {@code nothrow new[]} operator.
-            (<a href="http://code.google.com/p/android/issues/detail?id=52833">Issue 52833</a>)</li>
+            (<a href="http://b.android.com/52833">Issue 52833</a>)</li>
           <li>Fixed Gabi++ wrong offset to exception handler pointer.
             (<a href="https://android-review.googlesource.com/#/c/53446">Change 53446</a>)</li>
           <li>Removed Gabi++ redundant free on exception object
@@ -365,11 +638,11 @@
               <li>Fixed {@code stddef.h} to not redefine {@code offsetof} since it already exists
                 in the toolchain.</li>
               <li>Fixed {@code elf.h} to contain {@code Elf32_auxv_t} and {@code Elf64_auxv_t}.
-                (<a href="http://code.google.com/p/android/issues/detail?id=38441">Issue 38441</a>)
+                (<a href="http://b.android.com/38441">Issue 38441</a>)
                 </li>
               <li>Fixed the {@code #ifdef} C++ definitions in the
                 {@code OpenSLES_AndroidConfiguration.h} header file.
-                (<a href="http://code.google.com/p/android/issues/detail?id=53163">Issue 53163</a>)
+                (<a href="http://b.android.com/53163">Issue 53163</a>)
                 </li>
             </ul>
           </li>
@@ -377,7 +650,7 @@
             </li>
           <li>Fixed system and Gabi++ headers to be able to compile with API level 8 and lower.</li>
           <li>Fixed {@code cpufeatures} to not parse {@code /proc/self/auxv}.
-            (<a href="http://code.google.com/p/android/issues/detail?id=43055">Issue 43055</a>)</li>
+            (<a href="http://b.android.com/43055">Issue 43055</a>)</li>
           <li>Fixed {@code ld.gold} to not depend on host libstdc++ and on Windows platforms,
             to not depend on the {@code libgcc_sjlj_1.dll} library.</li>
           <li>Fixed Clang 3.1 which emits inconsistent register list in {@code .vsave} and fails
@@ -394,16 +667,16 @@
             </li>
           <li>Fixed X86 {@code libc.so} and {@code lib.a} which were missing the {@code sigsetjmp}
             and {@code siglongjmp} functions already declared in {@code setjmp.h}.
-            (<a href="http://code.google.com/p/android/issues/detail?id=19851">Issue 19851</a>)</li>
+            (<a href="http://b.android.com/19851">Issue 19851</a>)</li>
           <li>Patched GCC 4.4.3/4.6/4.7 libstdc++ to work with Clang in C++ 11.
             (<a href="http://clang.llvm.org/cxx_status.html">Clang Issue</a>)</li>
           <li>Fixed cygwin path in argument passed to {@code HOST_AWK}.</li>
           <li>Fixed {@code ndk-build} script warning in windows when running from project's JNI
             directory.
-            (<a href="http://code.google.com/p/android/issues/detail?id=40192">Issue 40192</a>)</li>
+            (<a href="http://b.android.com/40192">Issue 40192</a>)</li>
           <li>Fixed problem where the {@code ndk-build} script does not build if makefile has
             trailing whitespace in the {@code LOCAL_PATH} definition.
-            (<a href="http://code.google.com/p/android/issues/detail?id=42841">Issue 42841</a>)</li>
+            (<a href="http://b.android.com/42841">Issue 42841</a>)</li>
         </ul>
       </dd>
 
@@ -419,13 +692,13 @@
             hidden visibility except for exception handling helpers.</li>
           <li>Updated build so that {@code STLport} is built for ARM in Thumb mode.</li>
           <li>Added support for {@code std::set_new_handler} in Gabi++.
-            (<a href="http://code.google.com/p/android/issues/detail?id=52805">Issue 52805</a>)</li>
+            (<a href="http://b.android.com/52805">Issue 52805</a>)</li>
           <li>Enabled {@code FUTEX} system call in GNU libstdc++.</li>
           <li>Updated {@code ndk-build} so that it  no longer copies prebuilt static library to
             a project's {@code obj/local/&lt;abi&gt;/} directory.
-            (<a href="http://code.google.com/p/android/issues/detail?id=40302">Issue 40302</a>)</li>
+            (<a href="http://b.android.com/40302">Issue 40302</a>)</li>
           <li>Removed {@code __ARM_ARCH_5*__} from ARM {@code toolchains/*/setup.mk} script.
-            (<a href="http://code.google.com/p/android/issues/detail?id=21132">Issue 21132</a>)</li>
+            (<a href="http://b.android.com/21132">Issue 21132</a>)</li>
           <li>Built additional GNU libstdc++ libraries in thumb for ARM.</li>
           <li>Enabled MIPS floating-point {@code madd/msub/nmadd/nmsub/recip/rsqrt}
             instructions with 32-bit FPU.</li>
@@ -458,7 +731,7 @@
                 which was preventing a significant amount of parallel build processing.</li>
               <li>Updated {@code build-gabi++.sh} and {@code build-stlport.sh} so they can now run
                 from the NDK package.
-                (<a href="http://code.google.com/p/android/issues/detail?id=52835">Issue 52835</a>)
+                (<a href="http://b.android.com/52835">Issue 52835</a>)
                 </li>
               <li>Fixed {@code run-tests.sh} in the {@code MSys} utilities collection.</li>
               <li>Improved 64-bit host toolchain and Canadian Cross build support.</li>
@@ -540,7 +813,7 @@
       <dd>
         <ul>
           <li>Fixed unnecessary rebuild of object files when using the {@code ndk-build} script.
-            (<a href="http://code.google.com/p/android/issues/detail?id=39810">Issue 39810</a>)</li>
+            (<a href="http://b.android.com/39810">Issue 39810</a>)</li>
           <li>Fixed a linker failure with the NDK 8c release for Mac OS X 10.6.x that produced the
             following error:
             <pre>
@@ -551,29 +824,29 @@
             not compatible with Mac OS 10.6.x and the NDK.
           </li>
           <li>Removed the {@code -x c++} options from the Clang++ standalone build script.
-          (<a href="http://code.google.com/p/android/issues/detail?id=39089">Issue 39089</a>)</li>
+          (<a href="http://b.android.com/39089">Issue 39089</a>)</li>
           <li>Fixed issues using the {@code NDK_TOOLCHAIN_VERSION=clang3.1} option in Cygwin.
-           (<a href="http://code.google.com/p/android/issues/detail?id=39585">Issue 39585</a>)</li>
+           (<a href="http://b.android.com/39585">Issue 39585</a>)</li>
           <li>Fixed the {@code make-standalone-toolchain.sh} script to allow generation of a
             standalone toolchain using the Cygwin or MinGW environments. The resulting toolchain
             can be used in Cygwin, MingGW or CMD.exe environments.
-            (<a href="http://code.google.com/p/android/issues/detail?id=39915">Issue 39915</a>,
-            <a href="http://code.google.com/p/android/issues/detail?id=39585">Issue 39585</a>)</li>
+            (<a href="http://b.android.com/39915">Issue 39915</a>,
+            <a href="http://b.android.com/39585">Issue 39585</a>)</li>
           <li>Added missing {@code SL_IID_ANDROIDBUFFERQUEUESOURCE} option in android-14 builds for
             ARM and X86.
-            (<a href="http://code.google.com/p/android/issues/detail?id=40625">Issue 40625</a>)</li>
+            (<a href="http://b.android.com/40625">Issue 40625</a>)</li>
           <li>Fixed x86 CPU detection for the {@code ANDROID_CPU_X86_FEATURE_MOVBE} feature.
-            (<a href="http://code.google.com/p/android/issues/detail?id=39317">Issue 39317</a>)</li>
+            (<a href="http://b.android.com/39317">Issue 39317</a>)</li>
           <li>Fixed an issue preventing the Standard Template Library (STL) from using C++
             sources that do not have a {@code .cpp} file extension.</li>
           <li>Fixed GCC 4.6 ARM internal compiler error <em>at reload1.c:1061</em>.
-            (<a href="http://code.google.com/p/android/issues/detail?id=20862">Issue 20862</a>)</li>
+            (<a href="http://b.android.com/20862">Issue 20862</a>)</li>
           <li>Fixed GCC 4.4.3 ARM internal compiler error <em>at emit-rtl.c:1954</em>.
-            (<a href="http://code.google.com/p/android/issues/detail?id=22336">Issue 22336</a>)</li>
+            (<a href="http://b.android.com/22336">Issue 22336</a>)</li>
           <li>Fixed GCC 4.4.3 ARM internal compiler error <em>at postreload.c:396</em>.
-            (<a href="http://code.google.com/p/android/issues/detail?id=22345">Issue 22345</a>)</li>
+            (<a href="http://b.android.com/22345">Issue 22345</a>)</li>
           <li>Fixed problem with GCC 4.6/4.7 skipping lambda functions.
-            (<a href="http://code.google.com/p/android/issues/detail?id=35933">Issue 35933</a>)</li>
+            (<a href="http://b.android.com/35933">Issue 35933</a>)</li>
         </ul>
       </dd>
 
@@ -584,21 +857,21 @@
             <ul>
               <li>Fixed {@code __WINT_TYPE__} and {@code wint_t} to be the same type.</li>
               <li>Corrected typo in {@code android/bitmap.h}.
-                (<a href="http://code.google.com/p/android/issues/detail?id=15134">Issue 15134</a>)
+                (<a href="http://b.android.com/15134">Issue 15134</a>)
               </li>
               <li>Corrected typo in {@code errno.h}.</li>
               <li>Added check for the presence of {@code __STDC_VERSION__} in {@code sys/cdefs.h}.
-                (<a href="http://code.google.com/p/android/issues/detail?id=14627">Issue 14627</a>)
+                (<a href="http://b.android.com/14627">Issue 14627</a>)
               </li>
               <li>Reorganized headers in {@code byteswap.h} and {@code dirent.h}.</li>
               <li>Fixed {@code limits.h} to include {@code page.h} which provides {@code PAGE_SIZE}
                 settings.
-                (<a href="http://code.google.com/p/android/issues/detail?id=39983">Issue 39983</a>)
+                (<a href="http://b.android.com/39983">Issue 39983</a>)
               </li>
               <li>Fixed return type of {@code glGetAttribLocation()} and
                 {@code glGetUniformLocation()} from {@code int} to {@code GLint}.</li>
               <li>Fixed {@code __BYTE_ORDER} constant for x86 builds.
-                (<a href="http://code.google.com/p/android/issues/detail?id=39824">Issue 39824</a>)
+                (<a href="http://b.android.com/39824">Issue 39824</a>)
               </li>
             </ul>
           </li>
@@ -611,7 +884,7 @@
           <li>Fixed ARM EHABI support in Clang to conform to specifications.</li>
           <li>Fixed GNU Debugger (GDB) to shorten the time spent on walking the target's link map
             during {@code solib} events.
-            (<a href="http://code.google.com/p/android/issues/detail?id=38402">Issue 38402</a>)</li>
+            (<a href="http://b.android.com/38402">Issue 38402</a>)</li>
           <li>Fixed missing {@code libgcc.a} file when linking shared libraries.</li>
         </ul>
       </dd>
@@ -712,7 +985,7 @@
         <ul>
           <li>Fixed an issue where running {@code make-standalone-toolchain.sh} with root privileges
             resulted in the stand alone tool chain being inaccessible to some users.
-            (<a href="http://code.google.com/p/android/issues/detail?id=35279">Issue 35279</a>)
+            (<a href="http://b.android.com/35279">Issue 35279</a>)
             <ul>
               <li>All files and executables in the NDK release package are set to have read and
                 execute permissions for all.</li>
@@ -722,23 +995,23 @@
           <li>Removed redundant {@code \r} from Windows prebuilt {@code echo.exe}. The redundant
           {@code \r} caused {@code gdb.setup} to fail in the GNU Debugger (GDB) because it
           incorrectly became part of the path.
-          (<a href="http://code.google.com/p/android/issues/detail?id=36054">Issue 36054</a>)</li>
+          (<a href="http://b.android.com/36054">Issue 36054</a>)</li>
           <li>Fixed Windows parallel builds that sometimes failed due to timing issues in the
           {@code host-mkdir} implementation.
-          (<a href="http://code.google.com/p/android/issues/detail?id=25875">Issue 25875</a>)</li>
+          (<a href="http://b.android.com/25875">Issue 25875</a>)</li>
           <li>Fixed GCC 4.4.3 GNU {@code libstdc++} to <em>not</em> merge {@code typeinfo} names by
           default. For more details, see
           {@code toolchain repo gcc/gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo}.
-          (<a href="http://code.google.com/p/android/issues/detail?id=22165">Issue 22165</a>)</li>
+          (<a href="http://b.android.com/22165">Issue 22165</a>)</li>
           <li>Fixed problem on {@code null} context in GCC 4.6
           {@code cp/mangle.c::write_unscoped_name}, where GCC may crash when the context is
           {@code null} and dereferenced in {@code TREE_CODE}.</li>
           <li>Fixed GCC 4.4.3 crashes on ARM NEON-specific type definitions for floats.
-          (<a href="http://code.google.com/p/android/issues/detail?id=34613">Issue 34613</a>)</li>
+          (<a href="http://b.android.com/34613">Issue 34613</a>)</li>
           <li>Fixed the {@code STLport} internal {@code _IteWrapper::operator*()} implementation
           where a stale stack location holding the dereferenced value was returned and caused
           runtime crashes.
-          (<a href="http://code.google.com/p/android/issues/detail?id=38630">Issue 38630</a>)</li>
+          (<a href="http://b.android.com/38630">Issue 38630</a>)</li>
 
           <li>ARM-specific fixes:
             <ul>
@@ -755,17 +1028,17 @@
               <li>Fixed {@code binutils-2.21/ld.bfd} to be capable of linking object from older
               binutils without {@code tag_FP_arch}, which was producing <em>assertion fail</em>
               error messages in GNU Binutils.
-              (<a href="http://code.google.com/p/android/issues/detail?id=35209">Issue 35209</a>)
+              (<a href="http://b.android.com/35209">Issue 35209</a>)
               </li>
               <li>Removed <em>Unknown EABI object attribute 44</em> warning when
               {@code binutils-2.19/ld} links prebuilt object by newer {@code binutils-2.21}</li>
               <li>Fixed an issue in GNU {@code stdc++} compilation with both {@code -mthumb} and
               {@code -march=armv7-a}, by modifying {@code make-standalone-toolchain.sh} to populate
               {@code headers/libs} in sub-directory {@code armv7-a/thumb}.
-              (<a href="http://code.google.com/p/android/issues/detail?id=35616">Issue 35616</a>)
+              (<a href="http://b.android.com/35616">Issue 35616</a>)
               </li>
               <li>Fixed <em>unresolvable R_ARM_THM_CALL relocation</em> error.
-              (<a href="http://code.google.com/p/android/issues/detail?id=35342">Issue 35342</a>)
+              (<a href="http://b.android.com/35342">Issue 35342</a>)
               </li>
               <li>Fixed internal compiler error at {@code reload1.c:3633}, caused by the ARM
               back-end expecting the wrong operand type when sign-extend from {@code char}.
@@ -794,11 +1067,11 @@
               <li>Disabled Python support in gdb-7.x at build, otherwise the gdb-7.x configure
               function may pick up whatever Python version is available on the host and build
               {@code gdb} with a hard-wired dependency on a specific version of Python.
-              (<a href="http://code.google.com/p/android/issues/detail?id=36120">Issue 36120</a>)
+              (<a href="http://b.android.com/36120">Issue 36120</a>)
               </li>
               <li>Fixed {@code ndk-gdb} when {@code APP_ABI} contains {@code all} and matchs none
               of the known architectures.
-              (<a href="http://code.google.com/p/android/issues/detail?id=35392">Issue 35392</a>)
+              (<a href="http://b.android.com/35392">Issue 35392</a>)
               </li>
               <li>Fixed Windows pathname support, by keeping the {@code :} character if it looks
               like it could be part of a Windows path starting with a drive letter.
@@ -809,7 +1082,7 @@
               </li>
               <li>Added fix to only read the current {@code solibs} when the linker is consistent.
               This change speeds up {@code solib} event handling.
-              (<a href="http://code.google.com/p/android/issues/detail?id=37677">Issue 37677</a>)
+              (<a href="http://b.android.com/37677">Issue 37677</a>)
               </li>
               <li>Added fix to make repeated attempts to find {@code solib} breakpoints. GDB now
               retries {@code enable_break()} during every call to {@code svr4_current_sos()} until
@@ -817,13 +1090,13 @@
               (<a href="https://android-review.googlesource.com/#/c/43563">Change 43563</a>)</li>
               <li>Fixed an issue where {@code gdb} would not stop on breakpoints placed in
               {@code dlopen-ed} libraries.
-              (<a href="http://code.google.com/p/android/issues/detail?id=34856">Issue 34856</a>)
+              (<a href="http://b.android.com/34856">Issue 34856</a>)
               </li>
               <li>Fixed {@code SIGILL} in dynamic linker when calling {@code dlopen()}, on system
               where {@code /system/bin/linker} is stripped of symbols and
               {@code rtld_db_dlactivity()} is implemented as {@code Thumb}, due to not preserving
               {@code LSB} of {@code sym_addr}.
-              (<a href="http://code.google.com/p/android/issues/detail?id=37147">Issue 37147</a>)
+              (<a href="http://b.android.com/37147">Issue 37147</a>)
               </li>
             </ul>
           </li>
@@ -848,7 +1121,7 @@
               {@code __END_DECLS}.</li>
               <li>Removed unimplemented functions in {@code malloc.h}.</li>
               <li>Fixed {@code stdint.h} defintion of {@code uint64_t} for ANSI compilers.
-              (<a href="http://code.google.com/p/android/issues/detail?id=1952">Issue 1952</a>)</li>
+              (<a href="http://b.android.com/1952">Issue 1952</a>)</li>
               <li>Fixed preprocessor macros in {@code &lt;arch&gt;/include/machine/*}.</li>
               <li>Replaced {@code link.h} for MIPS with new version supporting all platforms.</li>
               <li>Removed {@code linux-unistd.h}</li>
@@ -904,7 +1177,7 @@
           {@code platforms/android-[3,4,5,8]}. Those headers were incomplete, since both X86 and
           MIPS ABIs are only supported at API 9 or higher.</li>
           <li>Simplified c++ include path in standalone packages, as shown below.
-          (<a href="http://code.google.com/p/android/issues/detail?id=35279">Issue 35279</a>)
+          (<a href="http://b.android.com/35279">Issue 35279</a>)
 <pre>
 &lt;path&gt;/arm-linux-androideabi/include/c++/4.6.x-google
   to:
@@ -916,7 +1189,7 @@
           <li>Fixed an issue in {@code samples/san-angeles} that caused a black screen or freeze
           frame on re-launch.</li>
           <li>Replaced deprecated APIs in NDK samples.
-          (<a href="http://code.google.com/p/android/issues/detail?id=20017">Issue 20017</a>)
+          (<a href="http://b.android.com/20017">Issue 20017</a>)
             <ul>
               <li>{@code hello-gl2} from android-5 to android-7</li>
               <li>{@code native-activity} from android-9 to android-10</li>
@@ -1196,7 +1469,7 @@
           <li>Fixed a typo in GAbi++ implementation where the result of {@code
           dynamic_cast&lt;D&gt;(b)} of base class object {@code b} to derived class {@code D} is
           incorrectly adjusted in the opposite direction from the base class.
-          (<a href="http://code.google.com/p/android/issues/detail?id=28721">Issue 28721</a>)
+          (<a href="http://b.android.com/28721">Issue 28721</a>)
           </li>
           <li>Fixed an issue in which {@code make-standalone-toolchain.sh} fails to copy
           {@code libsupc++.*}.</li>
@@ -1710,7 +1983,7 @@
             <li>Fixed the standalone toolchain linker warnings about missing the definition and
             size for the <code>__dso_handle</code> symbol (ARM only).</li>
             <li>Fixed the inclusion order of <code>$(SYSROOT)/usr/include</code> for x86 builds.
-            See the <a href="http://code.google.com/p/android/issues/detail?id=18540">bug</a> for
+            See the <a href="http://b.android.com/18540">bug</a> for
             more information.</li>
             <li>Fixed the definitions of <code>ptrdiff_t</code> and <code>size_t</code> in
             x86-specific systems when they are used with the x86 standalone toolchain.</li>
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index b58fdd1..cd2d986 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -29,6 +29,42 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>SDK Tools, Revision 22.0.4</a> <em>(July 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+    <dd>
+      <ul>
+        <li>Android SDK Platform-tools revision 16 or later.</li>
+        <li>If you are developing in Eclipse with the
+          <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a>, note that this version of
+          SDK Tools is designed for use with ADT 22.0.4 and later. If you haven't already, update
+          ADT to 22.0.4.</li>
+        <li>If you are using <a href="{@docRoot}sdk/installing/studio.html">Android Studio</a>,
+          note that this version of the SDK Tools is designed to work with Android Studio
+          0.2.x and later.</li>
+        <li>If you are developing without an integrated development environment (IDE), you must have
+          <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+      <ul>
+        <li>Fixed problem with compiling Renderscript code.</li>
+      </ul>
+    </dd>
+    </dl>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>SDK Tools, Revision 22.0.1</a> <em>(May 2013)</em>
   </p>
 
diff --git a/docs/html/training/implementing-navigation/nav-drawer.jd b/docs/html/training/implementing-navigation/nav-drawer.jd
index 527d570..38b73454 100644
--- a/docs/html/training/implementing-navigation/nav-drawer.jd
+++ b/docs/html/training/implementing-navigation/nav-drawer.jd
@@ -124,6 +124,7 @@
 <pre>
 public class MainActivity extends Activity {
     private String[] mPlanetTitles;
+    private DrawerLayout mDrawerLayout;
     private ListView mDrawerList;
     ...
 
@@ -133,6 +134,7 @@
         setContentView(R.layout.activity_main);
 
         mPlanetTitles = getResources().getStringArray(R.array.planets_array);
+        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
         mDrawerList = (ListView) findViewById(R.id.left_drawer);
 
         // Set the adapter for the list view
@@ -191,9 +193,9 @@
                    .commit();
 
     // Highlight the selected item, update the title, and close the drawer
-    mDrawer.setItemChecked(position, true);
+    mDrawerList.setItemChecked(position, true);
     setTitle(mPlanetTitles[position]);
-    mDrawerLayout.closeDrawer(mDrawer);
+    mDrawerLayout.closeDrawer(mDrawerList);
 }
 
 &#64;Override
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index af1a447..aaed094 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -95,21 +95,6 @@
      * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
      */
     public SurfaceTexture(int texName) {
-        this(texName, false);
-    }
-
-    /**
-     * Construct a new SurfaceTexture to stream images to a given OpenGL texture.
-     *
-     * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
-     * @param allowSynchronousMode whether the SurfaceTexture can run in the synchronous mode.
-     *      When the image stream comes from OpenGL, SurfaceTexture may run in the synchronous
-     *      mode where the producer side may be blocked to avoid skipping frames. To avoid the
-     *      thread block, set allowSynchronousMode to false.
-     *
-     * @hide
-     */
-    public SurfaceTexture(int texName, boolean allowSynchronousMode) {
         Looper looper;
         if ((looper = Looper.myLooper()) != null) {
             mEventHandler = new EventHandler(looper);
@@ -118,7 +103,7 @@
         } else {
             mEventHandler = null;
         }
-        nativeInit(texName, new WeakReference<SurfaceTexture>(this), allowSynchronousMode);
+        nativeInit(texName, new WeakReference<SurfaceTexture>(this));
     }
 
     /**
@@ -299,7 +284,7 @@
         }
     }
 
-    private native void nativeInit(int texName, Object weakSelf, boolean allowSynchronousMode);
+    private native void nativeInit(int texName, Object weakSelf);
     private native void nativeFinalize();
     private native void nativeGetTransformMatrix(float[] mtx);
     private native long nativeGetTimestamp();
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 6de8c8c..6ac637e 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -495,6 +495,10 @@
     }
 }
 
+void Caches::resetActiveTexture() {
+    mTextureUnit = -1;
+}
+
 void Caches::bindTexture(GLuint texture) {
     if (mBoundTextures[mTextureUnit] != texture) {
         glBindTexture(GL_TEXTURE_2D, texture);
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index b7a97ad..f8b1e17 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -226,6 +226,11 @@
     void activeTexture(GLuint textureUnit);
 
     /**
+     * Invalidate the cached value of the active texture unit.
+     */
+    void resetActiveTexture();
+
+    /**
      * Binds the specified texture as a GL_TEXTURE_2D texture.
      * All texture bindings must be performed with this method or
      * bindTexture(GLenum, GLuint).
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 73082c1..bd371a3 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -31,7 +31,6 @@
 Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight):
         caches(Caches::getInstance()), texture(caches) {
     mesh = NULL;
-    meshIndices = NULL;
     meshElementCount = 0;
     cacheable = true;
     dirty = false;
@@ -57,7 +56,6 @@
     deleteTexture();
 
     delete[] mesh;
-    delete[] meshIndices;
     delete deferredList;
 }
 
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index ebd5543..b70042f 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -277,7 +277,6 @@
      * If the layer can be rendered as a mesh, this is non-null.
      */
     TextureVertex* mesh;
-    uint16_t* meshIndices;
     GLsizei meshElementCount;
 
     /**
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index cfb1e97e..f8076cc 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -130,10 +130,7 @@
     if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
         if (mLayer->mesh) {
             delete[] mLayer->mesh;
-            delete[] mLayer->meshIndices;
-
             mLayer->mesh = NULL;
-            mLayer->meshIndices = NULL;
             mLayer->meshElementCount = 0;
         }
 
@@ -154,17 +151,11 @@
 
     if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
         delete[] mLayer->mesh;
-        delete[] mLayer->meshIndices;
-
         mLayer->mesh = NULL;
-        mLayer->meshIndices = NULL;
     }
 
-    bool rebuildIndices = false;
     if (!mLayer->mesh) {
         mLayer->mesh = new TextureVertex[count * 4];
-        mLayer->meshIndices = new uint16_t[elementCount];
-        rebuildIndices = true;
     }
     mLayer->meshElementCount = elementCount;
 
@@ -173,7 +164,6 @@
     const float height = mLayer->layer.getHeight();
 
     TextureVertex* mesh = mLayer->mesh;
-    uint16_t* indices = mLayer->meshIndices;
 
     for (size_t i = 0; i < count; i++) {
         const android::Rect* r = &rects[i];
@@ -187,17 +177,6 @@
         TextureVertex::set(mesh++, r->right, r->top, u2, v1);
         TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
         TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
-
-        if (rebuildIndices) {
-            uint16_t quad = i * 4;
-            int index = i * 6;
-            indices[index    ] = quad;       // top-left
-            indices[index + 1] = quad + 1;   // top-right
-            indices[index + 2] = quad + 2;   // bottom-left
-            indices[index + 3] = quad + 2;   // bottom-left
-            indices[index + 4] = quad + 1;   // top-right
-            indices[index + 5] = quad + 3;   // bottom-right
-        }
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 3e84273..bc00ce8 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -107,6 +107,15 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
+// Functions
+///////////////////////////////////////////////////////////////////////////////
+
+template<typename T>
+static inline T min(T a, T b) {
+    return a < b ? a : b;
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -351,6 +360,7 @@
             mCaches.currentProgram = NULL;
         }
     }
+    mCaches.resetActiveTexture();
     mCaches.unbindMeshBuffer();
     mCaches.unbindIndicesBuffer();
     mCaches.resetVertexPointers();
@@ -1284,7 +1294,6 @@
 
 void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color,
         SkXfermode::Mode mode, bool dirty) {
-    int count = 0;
     Vector<float> rects;
 
     SkRegion::Iterator it(region);
@@ -1294,11 +1303,10 @@
         rects.push(r.fTop);
         rects.push(r.fRight);
         rects.push(r.fBottom);
-        count += 4;
         it.next();
     }
 
-    drawColorRects(rects.array(), count, color, mode, true, dirty, false);
+    drawColorRects(rects.array(), rects.size(), color, mode, true, dirty, false);
 }
 
 void OpenGLRenderer::dirtyLayer(const float left, const float top,
@@ -1328,6 +1336,21 @@
     }
 }
 
+void OpenGLRenderer::drawIndexedQuads(Vertex* mesh, GLsizei quadsCount) {
+    GLsizei elementsCount = quadsCount * 6;
+    while (elementsCount > 0) {
+        GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+
+        setupDrawIndexedVertices(&mesh[0].position[0]);
+        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL);
+
+        elementsCount -= drawCount;
+        // Though there are 4 vertices in a quad, we use 6 indices per
+        // quad to draw with GL_TRIANGLES
+        mesh += (drawCount / 6) * 4;
+    }
+}
+
 void OpenGLRenderer::clearLayerRegions() {
     const size_t count = mLayers.size();
     if (count == 0) return;
@@ -1342,17 +1365,15 @@
         // is likely different so we need to disable clipping here
         bool scissorChanged = mCaches.disableScissor();
 
-        Vertex mesh[count * 6];
+        Vertex mesh[count * 4];
         Vertex* vertex = mesh;
 
         for (uint32_t i = 0; i < count; i++) {
             Rect* bounds = mLayers.itemAt(i);
 
-            Vertex::set(vertex++, bounds->left, bounds->bottom);
             Vertex::set(vertex++, bounds->left, bounds->top);
             Vertex::set(vertex++, bounds->right, bounds->top);
             Vertex::set(vertex++, bounds->left, bounds->bottom);
-            Vertex::set(vertex++, bounds->right, bounds->top);
             Vertex::set(vertex++, bounds->right, bounds->bottom);
 
             delete bounds;
@@ -1368,9 +1389,8 @@
         setupDrawProgram();
         setupDrawPureColorUniforms();
         setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
-        setupDrawVertices(&mesh[0].position[0]);
 
-        glDrawArrays(GL_TRIANGLES, 0, count * 6);
+        drawIndexedQuads(&mesh[0], count);
 
         if (scissorChanged) mCaches.enableScissor();
     } else {
@@ -1976,10 +1996,10 @@
     }
 }
 
-void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
+void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
     bool force = mCaches.unbindMeshBuffer();
+    mCaches.bindIndicesBuffer();
     mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
-    mCaches.unbindIndicesBuffer();
 }
 
 void OpenGLRenderer::finishDrawTexture() {
@@ -3139,11 +3159,22 @@
                 setupDrawModelViewTranslate(x, y,
                         x + layer->layer.getWidth(), y + layer->layer.getHeight());
             }
-            setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
 
-            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
-                    glDrawElements(GL_TRIANGLES, layer->meshElementCount,
-                            GL_UNSIGNED_SHORT, layer->meshIndices));
+            TextureVertex* mesh = &layer->mesh[0];
+            GLsizei elementsCount = layer->meshElementCount;
+
+            while (elementsCount > 0) {
+                GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+
+                setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
+                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
+                        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL));
+
+                elementsCount -= drawCount;
+                // Though there are 4 vertices in a quad, we use 6 indices per
+                // quad to draw with GL_TRIANGLES
+                mesh += (drawCount / 6) * 4;
+            }
 
             finishDrawTexture();
 
@@ -3361,8 +3392,7 @@
     float right = FLT_MIN;
     float bottom = FLT_MIN;
 
-    int vertexCount = 0;
-    Vertex mesh[count * 6];
+    Vertex mesh[count];
     Vertex* vertex = mesh;
 
     for (int index = 0; index < count; index += 4) {
@@ -3371,15 +3401,11 @@
         float r = rects[index + 2];
         float b = rects[index + 3];
 
-        Vertex::set(vertex++, l, b);
         Vertex::set(vertex++, l, t);
         Vertex::set(vertex++, r, t);
         Vertex::set(vertex++, l, b);
-        Vertex::set(vertex++, r, t);
         Vertex::set(vertex++, r, b);
 
-        vertexCount += 6;
-
         left = fminf(left, l);
         top = fminf(top, t);
         right = fmaxf(right, r);
@@ -3402,13 +3428,12 @@
     setupDrawColorUniforms();
     setupDrawShaderUniforms();
     setupDrawColorFilterUniforms();
-    setupDrawVertices((GLvoid*) &mesh[0].position[0]);
 
     if (dirty && hasLayer()) {
         dirtyLayer(left, top, right, bottom, currentTransform());
     }
 
-    glDrawArrays(GL_TRIANGLES, 0, vertexCount);
+    drawIndexedQuads(&mesh[0], count / 4);
 
     return DrawGlInfo::kStatusDrew;
 }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5e731b4..eb42540 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -850,6 +850,13 @@
             bool ignoreTransform, bool ignoreScale = false, bool dirty = true);
 
     /**
+     * Draws the specified list of vertices as quads using indexed GL_TRIANGLES.
+     * If the number of vertices to draw exceeds the number of indices we have
+     * pre-allocated, this method will generate several glDrawElements() calls.
+     */
+    void drawIndexedQuads(Vertex* mesh, GLsizei quadsCount);
+
+    /**
      * Draws text underline and strike-through if needed.
      *
      * @param text The text to decor
@@ -988,7 +995,7 @@
     void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
     void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors);
     void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords, GLuint vbo = 0);
-    void setupDrawVertices(GLvoid* vertices);
+    void setupDrawIndexedVertices(GLvoid* vertices);
     void finishDrawTexture();
     void accountForClear(SkXfermode::Mode mode);
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d88ed33..bcd0398 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1996,7 +1996,7 @@
         IAudioService service = getService();
         try {
             service.requestAudioFocus(streamType, durationHint, mICallBack, null,
-                    AudioService.IN_VOICE_COMM_FOCUS_ID,
+                    MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
                     mContext.getBasePackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
@@ -2012,7 +2012,7 @@
     public void abandonAudioFocusForCall() {
         IAudioService service = getService();
         try {
-            service.abandonAudioFocus(null, AudioService.IN_VOICE_COMM_FOCUS_ID);
+            service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID);
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e);
         }
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 5383d08..1e46f0a 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -99,7 +99,7 @@
      */
     private static final int NATIVE_EVENT_NEW_POS = 3;
 
-    private final static String TAG = "AudioRecord-Java";
+    private final static String TAG = "android.media.AudioRecord";
 
 
     //---------------------------------------------------------
@@ -421,7 +421,9 @@
      * @see AudioRecord#RECORDSTATE_RECORDING
      */
     public int getRecordingState() {
-        return mRecordingState;
+        synchronized (mRecordingStateLock) {
+            return mRecordingState;
+        }
     }
 
     /**
@@ -474,21 +476,21 @@
         case AudioFormat.CHANNEL_INVALID:
         default:
             loge("getMinBufferSize(): Invalid channel configuration.");
-            return AudioRecord.ERROR_BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
 
         // PCM_8BIT is not supported at the moment
         if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
             loge("getMinBufferSize(): Invalid audio format.");
-            return AudioRecord.ERROR_BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
 
         int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
         if (size == 0) {
-            return AudioRecord.ERROR_BAD_VALUE;
+            return ERROR_BAD_VALUE;
         }
         else if (size == -1) {
-            return AudioRecord.ERROR;
+            return ERROR;
         }
         else {
             return size;
@@ -585,6 +587,7 @@
         }
 
         if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
+                || (offsetInBytes + sizeInBytes < 0)  // detect integer overflow
                 || (offsetInBytes + sizeInBytes > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
@@ -609,6 +612,7 @@
         }
 
         if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
+                || (offsetInShorts + sizeInShorts < 0)  // detect integer overflow
                 || (offsetInShorts + sizeInShorts > audioData.length)) {
             return ERROR_BAD_VALUE;
         }
@@ -692,6 +696,9 @@
      *  {@link #ERROR_INVALID_OPERATION}
      */
     public int setNotificationMarkerPosition(int markerInFrames) {
+        if (mState == STATE_UNINITIALIZED) {
+            return ERROR_INVALID_OPERATION;
+        }
         return native_set_marker_pos(markerInFrames);
     }
 
@@ -704,6 +711,9 @@
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
      */
     public int setPositionNotificationPeriod(int periodInFrames) {
+        if (mState == STATE_UNINITIALIZED) {
+            return ERROR_INVALID_OPERATION;
+        }
         return native_set_pos_update_period(periodInFrames);
     }
 
@@ -769,9 +779,8 @@
                 }
                 break;
             default:
-                Log.e(TAG, "[ android.media.AudioRecord.NativeEventHandler ] " +
-                        "Unknown event type: " + msg.what);
-            break;
+                loge("Unknown native event type: " + msg.what);
+                break;
             }
         }
     };
@@ -837,11 +846,11 @@
     //------------------
 
     private static void logd(String msg) {
-        Log.d(TAG, "[ android.media.AudioRecord ] " + msg);
+        Log.d(TAG, msg);
     }
 
     private static void loge(String msg) {
-        Log.e(TAG, "[ android.media.AudioRecord ] " + msg);
+        Log.e(TAG, msg);
     }
 
 }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 5eb6d37..c178ae4 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -22,12 +22,12 @@
 import static android.media.AudioManager.RINGER_MODE_VIBRATE;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
-import android.app.PendingIntent.OnFinished;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
@@ -106,7 +106,7 @@
  *
  * @hide
  */
-public class AudioService extends IAudioService.Stub implements OnFinished {
+public class AudioService extends IAudioService.Stub {
 
     private static final String TAG = "AudioService";
 
@@ -145,34 +145,25 @@
     private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7;
     private static final int MSG_LOAD_SOUND_EFFECTS = 8;
     private static final int MSG_SET_FORCE_USE = 9;
-    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 10;
-    private static final int MSG_BT_HEADSET_CNCT_FAILED = 11;
-    private static final int MSG_RCDISPLAY_CLEAR = 12;
-    private static final int MSG_RCDISPLAY_UPDATE = 13;
-    private static final int MSG_SET_ALL_VOLUMES = 14;
-    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15;
-    private static final int MSG_REPORT_NEW_ROUTES = 16;
-    private static final int MSG_REEVALUATE_REMOTE = 17;
-    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 18;
-    private static final int MSG_RCC_NEW_VOLUME_OBS = 19;
-    private static final int MSG_SET_FORCE_BT_A2DP_USE = 20;
+    private static final int MSG_BT_HEADSET_CNCT_FAILED = 10;
+    private static final int MSG_SET_ALL_VOLUMES = 11;
+    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 12;
+    private static final int MSG_REPORT_NEW_ROUTES = 13;
+    private static final int MSG_SET_FORCE_BT_A2DP_USE = 14;
+    private static final int MSG_SET_RSX_CONNECTION_STATE = 15; // change remote submix connection
+    private static final int MSG_CHECK_MUSIC_ACTIVE = 16;
+    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 17;
+    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 18;
+    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 19;
+    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 20;
+    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 21;
+    private static final int MSG_UNLOAD_SOUND_EFFECTS = 22;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
-    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 21;
-    private static final int MSG_SET_A2DP_CONNECTION_STATE = 22;
+    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
+    private static final int MSG_SET_A2DP_CONNECTION_STATE = 101;
     // end of messages handled under wakelock
-    private static final int MSG_SET_RSX_CONNECTION_STATE = 23; // change remote submix connection
-    private static final int MSG_CHECK_MUSIC_ACTIVE = 24;
-    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 25;
-    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 26;
-    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27;
-    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 28;
-    private static final int MSG_PROMOTE_RCC = 29;
-    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 30;
-    private static final int MSG_UNLOAD_SOUND_EFFECTS = 31;
-    private static final int MSG_RCC_NEW_PLAYBACK_STATE = 32;
-    private static final int MSG_RCC_SEEK_REQUEST = 33;
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
     // Timeout for connection to bluetooth headset service
@@ -186,7 +177,7 @@
     private VolumeStreamState[] mStreamStates;
     private SettingsObserver mSettingsObserver;
 
-    private int mMode;
+    private int mMode = AudioSystem.MODE_NORMAL;
     // protects mRingerMode
     private final Object mSettingsLock = new Object();
 
@@ -213,7 +204,7 @@
     private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
 
    /** @hide Maximum volume index values for audio streams */
-    private final int[] MAX_STREAM_VOLUME = new int[] {
+    private static final int[] MAX_STREAM_VOLUME = new int[] {
         5,  // STREAM_VOICE_CALL
         7,  // STREAM_SYSTEM
         7,  // STREAM_RING
@@ -345,9 +336,6 @@
     // Broadcast receiver for device connections intent broadcasts
     private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
 
-    // Used to alter media button redirection when the phone is ringing.
-    private boolean mIsRinging = false;
-
     // Devices currently connected
     private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
 
@@ -468,6 +456,10 @@
     // and used later when/if disableSafeMediaVolume() is called.
     private StreamVolumeCommand mPendingVolumeCommand;
 
+    private PowerManager.WakeLock mAudioEventWakeLock;
+
+    private final MediaFocusControl mMediaFocusControl;
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -481,7 +473,7 @@
                 com.android.internal.R.bool.config_voice_capable);
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
 
         Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
@@ -495,11 +487,13 @@
                 com.android.internal.R.integer.config_soundEffectVolumeDb);
 
         mVolumePanel = new VolumePanel(context, this);
-        mMode = AudioSystem.MODE_NORMAL;
         mForcedUseForComm = AudioSystem.FORCE_NONE;
 
         createAudioSystemThread();
 
+        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
+                mContext, /*VolumeController*/ mVolumePanel, this);
+
         boolean cameraSoundForced = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_camera_sound_forced);
         mCameraSoundForced = new Boolean(cameraSoundForced);
@@ -528,6 +522,7 @@
         updateStreamVolumeAlias(false /*updateVolumes*/);
         createStreamStates();
 
+        readAndSetLowRamDevice();
         mMediaServerOk = true;
 
         // Call setRingerModeInt() to apply correct mute
@@ -568,20 +563,6 @@
 
         context.registerReceiver(mReceiver, intentFilter);
 
-        // Register for package removal intent broadcasts for media button receiver persistence
-        IntentFilter pkgFilter = new IntentFilter();
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
-        pkgFilter.addDataScheme("package");
-        context.registerReceiver(mReceiver, pkgFilter);
-
-        // Register for phone state monitoring
-        TelephonyManager tmgr = (TelephonyManager)
-                context.getSystemService(Context.TELEPHONY_SERVICE);
-        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
-
         mUseMasterVolume = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_useMasterVolume);
         restoreMasterVolume();
@@ -589,11 +570,6 @@
         mMasterVolumeRamp = context.getResources().getIntArray(
                 com.android.internal.R.array.config_masterVolumeRamp);
 
-        mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC],
-                MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
-        mHasRemotePlayback = false;
-        mMainRemoteIsActive = false;
-        postReevaluateRemote();
     }
 
     private void createAudioSystemThread() {
@@ -795,7 +771,7 @@
         broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
 
         // Restore the default media button receiver from the system settings
-        restoreMediaButtonReceiver();
+        mMediaFocusControl.restoreMediaButtonReceiver();
     }
 
     private int rescaleIndex(int index, int srcStream, int dstStream) {
@@ -817,8 +793,8 @@
     public void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
             String callingPackage) {
         if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
-        if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
-            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
+        if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
+            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
         } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
             adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage);
         }
@@ -847,7 +823,7 @@
             // don't play sounds for remote
             flags &= ~(AudioManager.FLAG_PLAY_SOUND|AudioManager.FLAG_FIXED_VOLUME);
             //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
-            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
+            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
         } else {
             adjustStreamVolume(streamType, direction, flags, callingPackage);
         }
@@ -1274,6 +1250,10 @@
         return AudioSystem.getMasterMute();
     }
 
+    protected static int getMaxStreamVolume(int streamType) {
+        return MAX_STREAM_VOLUME[streamType];
+    }
+
     /** @see AudioManager#getStreamVolume(int) */
     public int getStreamVolume(int streamType) {
         ensureValidStreamType(streamType);
@@ -2597,7 +2577,7 @@
             } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                 // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
                 // volume can have priority over STREAM_MUSIC
-                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
+                if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
                     if (DEBUG_VOL)
                         Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
                     return STREAM_REMOTE_MUSIC;
@@ -2637,7 +2617,7 @@
                 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
                 return AudioSystem.STREAM_NOTIFICATION;
             } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
+                if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
                     // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
                     // volume can have priority over STREAM_MUSIC
                     if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
@@ -2681,7 +2661,7 @@
      */
     private void queueMsgUnderWakeLock(Handler handler, int msg,
             int arg1, int arg2, Object obj, int delay) {
-        mMediaEventWakeLock.acquire();
+        mAudioEventWakeLock.acquire();
         sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
     }
 
@@ -3379,13 +3359,6 @@
             }
         }
 
-        private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
-            Settings.System.putStringForUser(mContentResolver,
-                                             Settings.System.MEDIA_BUTTON_RECEIVER,
-                                             receiver == null ? "" : receiver.flattenToString(),
-                                             UserHandle.USER_CURRENT);
-        }
-
         private void cleanupPlayer(MediaPlayer mp) {
             if (mp != null) {
                 try {
@@ -3469,6 +3442,8 @@
                     // process restarts after a crash, not the first time it is started.
                     AudioSystem.setParameters("restarting=true");
 
+                    readAndSetLowRamDevice();
+
                     // Restore device connection states
                     synchronized (mConnectedDevices) {
                         Set set = mConnectedDevices.entrySet();
@@ -3562,31 +3537,18 @@
                     setForceUse(msg.arg1, msg.arg2);
                     break;
 
-                case MSG_PERSIST_MEDIABUTTONRECEIVER:
-                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
-                    break;
-
-                case MSG_RCDISPLAY_CLEAR:
-                    onRcDisplayClear();
-                    break;
-
-                case MSG_RCDISPLAY_UPDATE:
-                    // msg.obj is guaranteed to be non null
-                    onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1);
-                    break;
-
                 case MSG_BT_HEADSET_CNCT_FAILED:
                     resetBluetoothSco();
                     break;
 
                 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
                     onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
-                    mMediaEventWakeLock.release();
+                    mAudioEventWakeLock.release();
                     break;
 
                 case MSG_SET_A2DP_CONNECTION_STATE:
                     onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1);
-                    mMediaEventWakeLock.release();
+                    mAudioEventWakeLock.release();
                     break;
 
                 case MSG_REPORT_NEW_ROUTES: {
@@ -3609,26 +3571,6 @@
                     break;
                 }
 
-                case MSG_REEVALUATE_REMOTE:
-                    onReevaluateRemote();
-                    break;
-
-                case MSG_RCC_NEW_PLAYBACK_INFO:
-                    onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */,
-                            ((Integer)msg.obj).intValue() /* value */);
-                    break;
-                case MSG_RCC_NEW_VOLUME_OBS:
-                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
-                            (IRemoteVolumeObserver)msg.obj /* rvo */);
-                    break;
-                case MSG_RCC_NEW_PLAYBACK_STATE:
-                    onNewPlaybackStateForRcc(msg.arg1 /* rccId */, msg.arg2 /* state */,
-                            (RccPlaybackState)msg.obj /* newState */);
-                    break;
-                case MSG_RCC_SEEK_REQUEST:
-                    onSetRemoteControlClientPlaybackPosition(msg.arg1 /* generationId */,
-                            ((Long)msg.obj).longValue() /* timeMs */);
-
                 case MSG_SET_RSX_CONNECTION_STATE:
                     onSetRsxConnectionState(msg.arg1/*available*/, msg.arg2/*address*/);
                     break;
@@ -3649,10 +3591,6 @@
                     onPersistSafeVolumeState(msg.arg1);
                     break;
 
-                case MSG_PROMOTE_RCC:
-                    onPromoteRcc(msg.arg1);
-                    break;
-
                 case MSG_BROADCAST_BT_CONNECTION_STATE:
                     onBroadcastScoConnectionState(msg.arg1);
                     break;
@@ -4130,21 +4068,6 @@
                         0,
                         null,
                         SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
-            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
-                    || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
-                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
-                    // a package is being removed, not replaced
-                    String packageName = intent.getData().getSchemeSpecificPart();
-                    if (packageName != null) {
-                        cleanupMediaButtonReceiverForPackage(packageName, true);
-                    }
-                }
-            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
-                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
-                String packageName = intent.getData().getSchemeSpecificPart();
-                if (packageName != null) {
-                    cleanupMediaButtonReceiverForPackage(packageName, false);
-                }
             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 AudioSystem.setParameters("screen_state=on");
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
@@ -4161,7 +4084,7 @@
                         null,
                         0);
                 // the current audio focus owner is no longer valid
-                discardAudioFocusOwner();
+                mMediaFocusControl.discardAudioFocusOwner();
 
                 // load volume settings for new user
                 readAudioSettings(true /*userSwitch*/);
@@ -4177,2214 +4100,102 @@
     }
 
     //==========================================================================================
-    // AudioFocus
+    // RemoteControlDisplay / RemoteControlClient / Remote info
     //==========================================================================================
-
-    /* constant to identify focus stack entry that is used to hold the focus while the phone
-     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
-     * entering and exiting calls.
-     */
-    public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
-
-    private final static Object mAudioFocusLock = new Object();
-
-    private final static Object mRingingLock = new Object();
-
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            if (state == TelephonyManager.CALL_STATE_RINGING) {
-                //Log.v(TAG, " CALL_STATE_RINGING");
-                synchronized(mRingingLock) {
-                    mIsRinging = true;
-                }
-            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
-                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
-                synchronized(mRingingLock) {
-                    mIsRinging = false;
-                }
-            }
-        }
-    };
-
-    /**
-     * Discard the current audio focus owner.
-     * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
-     * focus), remove it from the stack, and clear the remote control display.
-     */
-    private void discardAudioFocusOwner() {
-        synchronized(mAudioFocusLock) {
-            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
-                // notify the current focus owner it lost focus after removing it from stack
-                FocusStackEntry focusOwner = mFocusStack.pop();
-                try {
-                    focusOwner.mFocusDispatcher.dispatchAudioFocusChange(
-                            AudioManager.AUDIOFOCUS_LOSS, focusOwner.mClientId);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Failure to signal loss of audio focus due to "+ e);
-                    e.printStackTrace();
-                }
-                focusOwner.unlinkToDeath();
-                // clear RCD
-                synchronized(mRCStack) {
-                    clearRemoteControlDisplay_syncAfRcs();
-                }
-            }
-        }
-    }
-
-    private void notifyTopOfAudioFocusStack() {
-        // notify the top of the stack it gained focus
-        if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
-            if (canReassignAudioFocus()) {
-                try {
-                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
-                            AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
-
-    private static class FocusStackEntry {
-        public int mStreamType = -1;// no stream type
-        public IAudioFocusDispatcher mFocusDispatcher = null;
-        public IBinder mSourceRef = null;
-        public String mClientId;
-        public int mFocusChangeType;
-        public AudioFocusDeathHandler mHandler;
-        public String mPackageName;
-        public int mCallingUid;
-
-        public FocusStackEntry() {
-        }
-
-        public FocusStackEntry(int streamType, int duration,
-                IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
-                String pn, int uid) {
-            mStreamType = streamType;
-            mFocusDispatcher = afl;
-            mSourceRef = source;
-            mClientId = id;
-            mFocusChangeType = duration;
-            mHandler = hdlr;
-            mPackageName = pn;
-            mCallingUid = uid;
-        }
-
-        public void unlinkToDeath() {
-            try {
-                if (mSourceRef != null && mHandler != null) {
-                    mSourceRef.unlinkToDeath(mHandler, 0);
-                    mHandler = null;
-                }
-            } catch (java.util.NoSuchElementException e) {
-                Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()");
-            }
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            unlinkToDeath(); // unlink exception handled inside method
-            super.finalize();
-        }
-    }
-
-    private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the audio focus stack
-     */
-    private void dumpFocusStack(PrintWriter pw) {
-        pw.println("\nAudio Focus stack entries (last is top of stack):");
-        synchronized(mAudioFocusLock) {
-            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
-            while(stackIterator.hasNext()) {
-                FocusStackEntry fse = stackIterator.next();
-                pw.println("  source:" + fse.mSourceRef
-                        + " -- pack: " + fse.mPackageName
-                        + " -- client: " + fse.mClientId
-                        + " -- duration: " + fse.mFocusChangeType
-                        + " -- uid: " + fse.mCallingUid
-                        + " -- stream: " + fse.mStreamType);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mAudioFocusLock
-     * Remove a focus listener from the focus stack.
-     * @param clientToRemove the focus listener
-     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
-     *   focus, notify the next item in the stack it gained focus.
-     */
-    private void removeFocusStackEntry(String clientToRemove, boolean signal) {
-        // is the current top of the focus stack abandoning focus? (because of request, not death)
-        if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
-        {
-            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
-            FocusStackEntry fse = mFocusStack.pop();
-            fse.unlinkToDeath();
-            if (signal) {
-                // notify the new top of the stack it gained focus
-                notifyTopOfAudioFocusStack();
-                // there's a new top of the stack, let the remote control know
-                synchronized(mRCStack) {
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
-            }
-        } else {
-            // focus is abandoned by a client that's not at the top of the stack,
-            // no need to update focus.
-            // (using an iterator on the stack so we can safely remove an entry after having
-            //  evaluated it, traversal order doesn't matter here)
-            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
-            while(stackIterator.hasNext()) {
-                FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
-                if(fse.mClientId.equals(clientToRemove)) {
-                    Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
-                            + fse.mClientId);
-                    stackIterator.remove();
-                    fse.unlinkToDeath();
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mAudioFocusLock
-     * Remove focus listeners from the focus stack for a particular client when it has died.
-     */
-    private void removeFocusStackEntryForClient(IBinder cb) {
-        // is the owner of the audio focus part of the client to remove?
-        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
-                mFocusStack.peek().mSourceRef.equals(cb);
-        // (using an iterator on the stack so we can safely remove an entry after having
-        //  evaluated it, traversal order doesn't matter here)
-        Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
-        while(stackIterator.hasNext()) {
-            FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
-            if(fse.mSourceRef.equals(cb)) {
-                Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
-                        + fse.mClientId);
-                stackIterator.remove();
-                // the client just died, no need to unlink to its death
-            }
-        }
-        if (isTopOfStackForClientToRemove) {
-            // we removed an entry at the top of the stack:
-            //  notify the new top of the stack it gained focus.
-            notifyTopOfAudioFocusStack();
-            // there's a new top of the stack, let the remote control know
-            synchronized(mRCStack) {
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
-     */
-    private boolean canReassignAudioFocus() {
-        // focus requests are rejected during a phone call or when the phone is ringing
-        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
-        if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
-     * stack if necessary.
-     */
-    private class AudioFocusDeathHandler implements IBinder.DeathRecipient {
-        private IBinder mCb; // To be notified of client's death
-
-        AudioFocusDeathHandler(IBinder cb) {
-            mCb = cb;
-        }
-
-        public void binderDied() {
-            synchronized(mAudioFocusLock) {
-                Log.w(TAG, "  AudioFocus   audio focus client died");
-                removeFocusStackEntryForClient(mCb);
-            }
-        }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
-    }
-
-
-    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int)  */
-    public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
-        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
-        // the main stream type for the audio focus request is currently not used. It may
-        // potentially be used to handle multiple stream type-dependent audio focuses.
-
-        // we need a valid binder callback for clients
-        if (!cb.pingBinder()) {
-            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
-            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-        }
-
-        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
-                callingPackageName) != AppOpsManager.MODE_ALLOWED) {
-            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-        }
-
-        synchronized(mAudioFocusLock) {
-            if (!canReassignAudioFocus()) {
-                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-            }
-
-            // handle the potential premature death of the new holder of the focus
-            // (premature death == death before abandoning focus)
-            // Register for client death notification
-            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
-            try {
-                cb.linkToDeath(afdh, 0);
-            } catch (RemoteException e) {
-                // client has already died!
-                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
-                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-            }
-
-            if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
-                // if focus is already owned by this client and the reason for acquiring the focus
-                // hasn't changed, don't do anything
-                if (mFocusStack.peek().mFocusChangeType == focusChangeHint) {
-                    // unlink death handler so it can be gc'ed.
-                    // linkToDeath() creates a JNI global reference preventing collection.
-                    cb.unlinkToDeath(afdh, 0);
-                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-                }
-                // the reason for the audio focus request has changed: remove the current top of
-                // stack and respond as if we had a new focus owner
-                FocusStackEntry fse = mFocusStack.pop();
-                fse.unlinkToDeath();
-            }
-
-            // notify current top of stack it is losing focus
-            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
-                try {
-                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
-                            -1 * focusChangeHint, // loss and gain codes are inverse of each other
-                            mFocusStack.peek().mClientId);
-                } catch (RemoteException e) {
-                    Log.e(TAG, " Failure to signal loss of focus due to "+ e);
-                    e.printStackTrace();
-                }
-            }
-
-            // focus requester might already be somewhere below in the stack, remove it
-            removeFocusStackEntry(clientId, false /* signal */);
-
-            // push focus requester at the top of the audio focus stack
-            mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
-                    clientId, afdh, callingPackageName, Binder.getCallingUid()));
-
-            // there's a new top of the stack, let the remote control know
-            synchronized(mRCStack) {
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
-        }//synchronized(mAudioFocusLock)
-
-        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-    }
-
-    /** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener)  */
-    public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
-        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
-        try {
-            // this will take care of notifying the new focus owner if needed
-            synchronized(mAudioFocusLock) {
-                removeFocusStackEntry(clientId, true);
-            }
-        } catch (java.util.ConcurrentModificationException cme) {
-            // Catching this exception here is temporary. It is here just to prevent
-            // a crash seen when the "Silent" notification is played. This is believed to be fixed
-            // but this try catch block is left just to be safe.
-            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
-            cme.printStackTrace();
-        }
-
-        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-    }
-
-
-    public void unregisterAudioFocusClient(String clientId) {
-        synchronized(mAudioFocusLock) {
-            removeFocusStackEntry(clientId, false);
-        }
-    }
-
-
-    //==========================================================================================
-    // RemoteControl
-    //==========================================================================================
-    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
-    }
-
-    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
-        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
-    }
-
-    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        // sanity check on the incoming key event
-        if (!isValidMediaKeyEvent(keyEvent)) {
-            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
-            return;
-        }
-        // event filtering for telephony
-        synchronized(mRingingLock) {
-            synchronized(mRCStack) {
-                if ((mMediaReceiverForCalls != null) &&
-                        (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) {
-                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
-                    return;
-                }
-            }
-        }
-        // event filtering based on voice-based interactions
-        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
-            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
-        } else {
-            dispatchMediaKeyEvent(keyEvent, needWakeLock);
-        }
-    }
-
-    /**
-     * Handles the dispatching of the media button events to the telephony package.
-     * Precondition: mMediaReceiverForCalls != null
-     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
-        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
-        }
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                    null, mKeyEventDone, mAudioHandler, Activity.RESULT_OK, null, null);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    /**
-     * Handles the dispatching of the media button events to one of the registered listeners,
-     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
-     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-        }
-        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        synchronized(mRCStack) {
-            if (!mRCStack.empty()) {
-                // send the intent that was registered by the client
-                try {
-                    mRCStack.peek().mMediaIntent.send(mContext,
-                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
-                            keyIntent, AudioService.this, mAudioHandler);
-                } catch (CanceledException e) {
-                    Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
-                    e.printStackTrace();
-                }
-            } else {
-                // legacy behavior when nobody registered their media button event receiver
-                //    through AudioManager
-                if (needWakeLock) {
-                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
-                }
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                            null, mKeyEventDone,
-                            mAudioHandler, Activity.RESULT_OK, null, null);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-            }
-        }
-    }
-
-    /**
-     * The different actions performed in response to a voice button key event.
-     */
-    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
-    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
-    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
-
-    private final Object mVoiceEventLock = new Object();
-    private boolean mVoiceButtonDown;
-    private boolean mVoiceButtonHandled;
-
-    /**
-     * Filter key events that may be used for voice-based interactions
-     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
-     *    media buttons that can be used to trigger voice-based interactions.
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        if (DEBUG_RC) {
-            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
-        }
-
-        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
-        int keyAction = keyEvent.getAction();
-        synchronized (mVoiceEventLock) {
-            if (keyAction == KeyEvent.ACTION_DOWN) {
-                if (keyEvent.getRepeatCount() == 0) {
-                    // initial down
-                    mVoiceButtonDown = true;
-                    mVoiceButtonHandled = false;
-                } else if (mVoiceButtonDown && !mVoiceButtonHandled
-                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
-                    // long-press, start voice-based interactions
-                    mVoiceButtonHandled = true;
-                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
-                }
-            } else if (keyAction == KeyEvent.ACTION_UP) {
-                if (mVoiceButtonDown) {
-                    // voice button up
-                    mVoiceButtonDown = false;
-                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
-                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
-                    }
-                }
-            }
-        }//synchronized (mVoiceEventLock)
-
-        // take action after media button event filtering for voice-based interactions
-        switch (voiceButtonAction) {
-            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
-                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
-                break;
-            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
-                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
-                // then start the voice-based interactions
-                startVoiceBasedInteractions(needWakeLock);
-                break;
-            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
-                if (DEBUG_RC) Log.v(TAG, "   send simulated key event, wakelock=" + needWakeLock);
-                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
-                break;
-        }
-    }
-
-    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
-        // send DOWN event
-        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
-        dispatchMediaKeyEvent(keyEvent, needWakeLock);
-        // send UP event
-        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
-        dispatchMediaKeyEvent(keyEvent, needWakeLock);
-
-    }
-
-
-    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
-        if (keyEvent == null) {
-            return false;
-        }
-        final int keyCode = keyEvent.getKeyCode();
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-            case KeyEvent.KEYCODE_MEDIA_CLOSE:
-            case KeyEvent.KEYCODE_MEDIA_EJECT:
-            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
-                break;
-            default:
-                return false;
-        }
-        return true;
-    }
-
-    /**
-     * Checks whether the given key code is one that can trigger the launch of voice-based
-     *   interactions.
-     * @param keyCode the key code associated with the key event
-     * @return true if the key is one of the supported voice-based interaction triggers
-     */
-    private static boolean isValidVoiceInputKeyCode(int keyCode) {
-        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Tell the system to start voice-based interactions / voice commands
-     */
-    private void startVoiceBasedInteractions(boolean needWakeLock) {
-        Intent voiceIntent = null;
-        // select which type of search to launch:
-        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
-        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
-        //    with EXTRA_SECURE set to true if the device is securely locked
-        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
-        if (!isLocked && pm.isScreenOn()) {
-            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
-            Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
-        } else {
-            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
-                    isLocked && mKeyguardManager.isKeyguardSecure());
-            Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
-        }
-        // start the search activity
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-        }
-        try {
-            if (voiceIntent != null) {
-                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                mContext.startActivity(voiceIntent);
-            }
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "No activity for search: " + e);
-        } finally {
-            if (needWakeLock) {
-                mMediaEventWakeLock.release();
-            }
-        }
-    }
-
-    private PowerManager.WakeLock mMediaEventWakeLock;
-
-    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
-
-    // only set when wakelock was acquired, no need to check value when received
-    private static final String EXTRA_WAKELOCK_ACQUIRED =
-            "android.media.AudioService.WAKELOCK_ACQUIRED";
-
-    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
-            int resultCode, String resultData, Bundle resultExtras) {
-        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
-            mMediaEventWakeLock.release();
-        }
-    }
-
-    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            if (intent == null) {
-                return;
-            }
-            Bundle extras = intent.getExtras();
-            if (extras == null) {
-                return;
-            }
-            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
-                mMediaEventWakeLock.release();
-            }
-        }
-    };
-
-    /**
-     * Synchronization on mCurrentRcLock always inside a block synchronized on mRCStack
-     */
-    private final Object mCurrentRcLock = new Object();
-    /**
-     * The one remote control client which will receive a request for display information.
-     * This object may be null.
-     * Access protected by mCurrentRcLock.
-     */
-    private IRemoteControlClient mCurrentRcClient = null;
-
-    private final static int RC_INFO_NONE = 0;
-    private final static int RC_INFO_ALL =
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
-
-    /**
-     * A monotonically increasing generation counter for mCurrentRcClient.
-     * Only accessed with a lock on mCurrentRcLock.
-     * No value wrap-around issues as we only act on equal values.
-     */
-    private int mCurrentRcClientGen = 0;
-
-    /**
-     * Inner class to monitor remote control client deaths, and remove the client for the
-     * remote control stack if necessary.
-     */
-    private class RcClientDeathHandler implements IBinder.DeathRecipient {
-        final private IBinder mCb; // To be notified of client's death
-        final private PendingIntent mMediaIntent;
-
-        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
-            mCb = cb;
-            mMediaIntent = pi;
-        }
-
-        public void binderDied() {
-            Log.w(TAG, "  RemoteControlClient died");
-            // remote control client died, make sure the displays don't use it anymore
-            //  by setting its remote control client to null
-            registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
-            // the dead client was maybe handling remote playback, reevaluate
-            postReevaluateRemote();
-        }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
-    }
-
-    /**
-     * A global counter for RemoteControlClient identifiers
-     */
-    private static int sLastRccId = 0;
-
-    private class RemotePlaybackState {
-        int mRccId;
-        int mVolume;
-        int mVolumeMax;
-        int mVolumeHandling;
-
-        private RemotePlaybackState(int id, int vol, int volMax) {
-            mRccId = id;
-            mVolume = vol;
-            mVolumeMax = volMax;
-            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
-        }
-    }
-
-    /**
-     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
-     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
-     * every time we need this info.
-     */
-    private RemotePlaybackState mMainRemote;
-    /**
-     * Indicates whether the "main" RemoteControlClient is considered active.
-     * Use synchronized on mMainRemote.
-     */
-    private boolean mMainRemoteIsActive;
-    /**
-     * Indicates whether there is remote playback going on. True even if there is no "active"
-     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
-     * handles remote playback.
-     * Use synchronized on mMainRemote.
-     */
-    private boolean mHasRemotePlayback;
-
-    private static class RccPlaybackState {
-        public int mState;
-        public long mPositionMs;
-        public float mSpeed;
-
-        public RccPlaybackState(int state, long positionMs, float speed) {
-            mState = state;
-            mPositionMs = positionMs;
-            mSpeed = speed;
-        }
-
-        public void reset() {
-            mState = RemoteControlClient.PLAYSTATE_STOPPED;
-            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
-            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
-        }
-
-        @Override
-        public String toString() {
-            return stateToString() + ", "
-                    + ((mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) ?
-                            "PLAYBACK_POSITION_INVALID ," : String.valueOf(mPositionMs)) + "ms ,"
-                    + mSpeed + "X";
-        }
-
-        private String stateToString() {
-            switch (mState) {
-                case RemoteControlClient.PLAYSTATE_NONE:
-                    return "PLAYSTATE_NONE";
-                case RemoteControlClient.PLAYSTATE_STOPPED:
-                    return "PLAYSTATE_STOPPED";
-                case RemoteControlClient.PLAYSTATE_PAUSED:
-                    return "PLAYSTATE_PAUSED";
-                case RemoteControlClient.PLAYSTATE_PLAYING:
-                    return "PLAYSTATE_PLAYING";
-                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-                    return "PLAYSTATE_FAST_FORWARDING";
-                case RemoteControlClient.PLAYSTATE_REWINDING:
-                    return "PLAYSTATE_REWINDING";
-                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                    return "PLAYSTATE_SKIPPING_FORWARDS";
-                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-                    return "PLAYSTATE_SKIPPING_BACKWARDS";
-                case RemoteControlClient.PLAYSTATE_BUFFERING:
-                    return "PLAYSTATE_BUFFERING";
-                case RemoteControlClient.PLAYSTATE_ERROR:
-                    return "PLAYSTATE_ERROR";
-                default:
-                    return "[invalid playstate]";
-            }
-        }
-    }
-
-    private static class RemoteControlStackEntry implements DeathRecipient {
-        public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        final public AudioService mService;
-        /**
-         * The target for the ACTION_MEDIA_BUTTON events.
-         * Always non null.
-         */
-        final public PendingIntent mMediaIntent;
-        /**
-         * The registered media button event receiver.
-         * Always non null.
-         */
-        final public ComponentName mReceiverComponent;
-        public IBinder mToken;
-        public String mCallingPackageName;
-        public int mCallingUid;
-        /**
-         * Provides access to the information to display on the remote control.
-         * May be null (when a media button event receiver is registered,
-         *     but no remote control client has been registered) */
-        public IRemoteControlClient mRcClient;
-        public RcClientDeathHandler mRcClientDeathHandler;
-        /**
-         * Information only used for non-local playback
-         */
-        public int mPlaybackType;
-        public int mPlaybackVolume;
-        public int mPlaybackVolumeMax;
-        public int mPlaybackVolumeHandling;
-        public int mPlaybackStream;
-        public RccPlaybackState mPlaybackState;
-        public IRemoteVolumeObserver mRemoteVolumeObs;
-
-        public void resetPlaybackInfo() {
-            mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
-            mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
-            mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
-            mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
-            mPlaybackStream = AudioManager.STREAM_MUSIC;
-            mPlaybackState.reset();
-            mRemoteVolumeObs = null;
-        }
-
-        /** precondition: mediaIntent != null */
-        public RemoteControlStackEntry(AudioService service, PendingIntent mediaIntent,
-                ComponentName eventReceiver, IBinder token) {
-            mService = service;
-            mMediaIntent = mediaIntent;
-            mReceiverComponent = eventReceiver;
-            mToken = token;
-            mCallingUid = -1;
-            mRcClient = null;
-            mRccId = ++sLastRccId;
-            mPlaybackState = new RccPlaybackState(
-                    RemoteControlClient.PLAYSTATE_STOPPED,
-                    RemoteControlClient.PLAYBACK_POSITION_INVALID,
-                    RemoteControlClient.PLAYBACK_SPEED_1X);
-
-            resetPlaybackInfo();
-            if (mToken != null) {
-                try {
-                    mToken.linkToDeath(this, 0);
-                } catch (RemoteException e) {
-                    mService.mAudioHandler.post(new Runnable() {
-                        @Override public void run() {
-                            mService.unregisterMediaButtonIntent(mMediaIntent);
-                        }
-                    });
-                }
-            }
-        }
-
-        public void unlinkToRcClientDeath() {
-            if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
-                try {
-                    mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
-                    mRcClientDeathHandler = null;
-                } catch (java.util.NoSuchElementException e) {
-                    // not much we can do here
-                    Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
-                    e.printStackTrace();
-                }
-            }
-        }
-
-        public void destroy() {
-            unlinkToRcClientDeath();
-            if (mToken != null) {
-                mToken.unlinkToDeath(this, 0);
-                mToken = null;
-            }
-        }
-
-        @Override
-        public void binderDied() {
-            mService.unregisterMediaButtonIntent(mMediaIntent);
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            destroy(); // unlink exception handled inside method
-            super.finalize();
-        }
-    }
-
-    /**
-     *  The stack of remote control event receivers.
-     *  Code sections and methods that modify the remote control event receiver stack are
-     *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
-     *  stack, audio focus or RC, can lead to a change in the remote control display
-     */
-    private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
-
-    /**
-     * The component the telephony package can register so telephony calls have priority to
-     * handle media button events
-     */
-    private ComponentName mMediaReceiverForCalls = null;
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the remote control focus stack
-     */
-    private void dumpRCStack(PrintWriter pw) {
-        pw.println("\nRemote Control stack entries (last is top of stack):");
-        synchronized(mRCStack) {
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                pw.println("  pi: " + rcse.mMediaIntent +
-                        " -- pack: " + rcse.mCallingPackageName +
-                        "  -- ercvr: " + rcse.mReceiverComponent +
-                        "  -- client: " + rcse.mRcClient +
-                        "  -- uid: " + rcse.mCallingUid +
-                        "  -- type: " + rcse.mPlaybackType +
-                        "  state: " + rcse.mPlaybackState);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the remote control stack, focusing
-     * on RemoteControlClient data
-     */
-    private void dumpRCCStack(PrintWriter pw) {
-        pw.println("\nRemote Control Client stack entries (last is top of stack):");
-        synchronized(mRCStack) {
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                pw.println("  uid: " + rcse.mCallingUid +
-                        "  -- id: " + rcse.mRccId +
-                        "  -- type: " + rcse.mPlaybackType +
-                        "  -- state: " + rcse.mPlaybackState +
-                        "  -- vol handling: " + rcse.mPlaybackVolumeHandling +
-                        "  -- vol: " + rcse.mPlaybackVolume +
-                        "  -- volMax: " + rcse.mPlaybackVolumeMax +
-                        "  -- volObs: " + rcse.mRemoteVolumeObs);
-            }
-            synchronized(mCurrentRcLock) {
-                pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
-            }
-        }
-        synchronized (mMainRemote) {
-            pw.println("\nRemote Volume State:");
-            pw.println("  has remote: " + mHasRemotePlayback);
-            pw.println("  is remote active: " + mMainRemoteIsActive);
-            pw.println("  rccId: " + mMainRemote.mRccId);
-            pw.println("  volume handling: "
-                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
-                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
-            pw.println("  volume: " + mMainRemote.mVolume);
-            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the list of remote control displays
-     */
-    private void dumpRCDList(PrintWriter pw) {
-        pw.println("\nRemote Control Display list entries:");
-        synchronized(mRCStack) {
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                pw.println("  IRCD: " + di.mRcDisplay +
-                        "  -- w:" + di.mArtworkExpectedWidth +
-                        "  -- h:" + di.mArtworkExpectedHeight+
-                        "  -- wantsPosSync:" + di.mWantsPositionSync);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Remove any entry in the remote control stack that has the same package name as packageName
-     * Pre-condition: packageName != null
-     */
-    private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) {
-        synchronized(mRCStack) {
-            if (mRCStack.empty()) {
-                return;
-            } else {
-                final PackageManager pm = mContext.getPackageManager();
-                RemoteControlStackEntry oldTop = mRCStack.peek();
-                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-                // iterate over the stack entries
-                // (using an iterator on the stack so we can safely remove an entry after having
-                //  evaluated it, traversal order doesn't matter here)
-                while(stackIterator.hasNext()) {
-                    RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
-                    if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
-                        // a stack entry is from the package being removed, remove it from the stack
-                        stackIterator.remove();
-                        rcse.destroy();
-                    } else if (rcse.mReceiverComponent != null) {
-                        try {
-                            // Check to see if this receiver still exists.
-                            pm.getReceiverInfo(rcse.mReceiverComponent, 0);
-                        } catch (PackageManager.NameNotFoundException e) {
-                            // Not found -- remove it!
-                            stackIterator.remove();
-                            rcse.destroy();
-                        }
-                    }
-                }
-                if (mRCStack.empty()) {
-                    // no saved media button receiver
-                    mAudioHandler.sendMessage(
-                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
-                                    null));
-                } else if (oldTop != mRCStack.peek()) {
-                    // the top of the stack has changed, save it in the system settings
-                    // by posting a message to persist it; only do this however if it has
-                    // a concrete component name (is not a transient registration)
-                    RemoteControlStackEntry rcse = mRCStack.peek();
-                    if (rcse.mReceiverComponent != null) {
-                        mAudioHandler.sendMessage(
-                                mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
-                                        rcse.mReceiverComponent));
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Restore remote control receiver from the system settings.
-     */
-    private void restoreMediaButtonReceiver() {
-        String receiverName = Settings.System.getStringForUser(mContentResolver,
-                Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
-        if ((null != receiverName) && !receiverName.isEmpty()) {
-            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
-            if (eventReceiver == null) {
-                // an invalid name was persisted
-                return;
-            }
-            // construct a PendingIntent targeted to the restored component name
-            // for the media button and register it
-            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-            //     the associated intent will be handled by the component being registered
-            mediaButtonIntent.setComponent(eventReceiver);
-            PendingIntent pi = PendingIntent.getBroadcast(mContext,
-                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
-            registerMediaButtonIntent(pi, eventReceiver, null);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Set the new remote control receiver at the top of the RC focus stack.
-     * Called synchronized on mAudioFocusLock, then mRCStack
-     * precondition: mediaIntent != null
-     */
-    private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target,
-            IBinder token) {
-        // already at top of stack?
-        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
-            return;
-        }
-        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
-                mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
-            return;
-        }
-        RemoteControlStackEntry rcse = null;
-        boolean wasInsideStack = false;
-        try {
-            for (int index = mRCStack.size()-1; index >= 0; index--) {
-                rcse = mRCStack.elementAt(index);
-                if(rcse.mMediaIntent.equals(mediaIntent)) {
-                    // ok to remove element while traversing the stack since we're leaving the loop
-                    mRCStack.removeElementAt(index);
-                    wasInsideStack = true;
-                    break;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // not expected to happen, indicates improper concurrent modification
-            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-        }
-        if (!wasInsideStack) {
-            rcse = new RemoteControlStackEntry(this, mediaIntent, target, token);
-        }
-        mRCStack.push(rcse); // rcse is never null
-
-        // post message to persist the default media button receiver
-        if (target != null) {
-            mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
-                    MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
-        }
-    }
-
-    /**
-     * Helper function:
-     * Remove the remote control receiver from the RC focus stack.
-     * Called synchronized on mAudioFocusLock, then mRCStack
-     * precondition: pi != null
-     */
-    private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) {
-        try {
-            for (int index = mRCStack.size()-1; index >= 0; index--) {
-                final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                if (rcse.mMediaIntent.equals(pi)) {
-                    rcse.destroy();
-                    // ok to remove element while traversing the stack since we're leaving the loop
-                    mRCStack.removeElementAt(index);
-                    break;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // not expected to happen, indicates improper concurrent modification
-            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mRCStack
-     */
-    private boolean isCurrentRcController(PendingIntent pi) {
-        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
-            return true;
-        }
-        return false;
-    }
-
-    //==========================================================================================
-    // Remote control display / client
-    //==========================================================================================
-    /**
-     * Update the remote control displays with the new "focused" client generation
-     */
-    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
-            PendingIntent newMediaIntent, boolean clearing) {
-        synchronized(mRCStack) {
-            if (mRcDisplays.size() > 0) {
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di = displayIterator.next();
-                    try {
-                        di.mRcDisplay.setCurrentClientId(
-                                newClientGeneration, newMediaIntent, clearing);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
-                        di.release();
-                        displayIterator.remove();
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Update the remote control clients with the new "focused" client generation
-     */
-    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
-        // (using an iterator on the stack so we can safely remove an entry if needed,
-        //  traversal order doesn't matter here as we update all entries)
-        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-        while(stackIterator.hasNext()) {
-            RemoteControlStackEntry se = stackIterator.next();
-            if ((se != null) && (se.mRcClient != null)) {
-                try {
-                    se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
-                    stackIterator.remove();
-                    se.unlinkToRcClientDeath();
-                }
-            }
-        }
-    }
-
-    /**
-     * Update the displays and clients with the new "focused" client generation and name
-     * @param newClientGeneration the new generation value matching a client update
-     * @param newMediaIntent the media button event receiver associated with the client.
-     *    May be null, which implies there is no registered media button event receiver.
-     * @param clearing true if the new client generation value maps to a remote control update
-     *    where the display should be cleared.
-     */
-    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
-            PendingIntent newMediaIntent, boolean clearing) {
-        // send the new valid client generation ID to all displays
-        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
-        // send the new valid client generation ID to all clients
-        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_CLEAR event
-     */
-    private void onRcDisplayClear() {
-        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
-
-        synchronized(mRCStack) {
-            synchronized(mCurrentRcLock) {
-                mCurrentRcClientGen++;
-                // synchronously update the displays and clients with the new client generation
-                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                        null /*newMediaIntent*/, true /*clearing*/);
-            }
-        }
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_UPDATE event
-     */
-    private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
-        synchronized(mRCStack) {
-            synchronized(mCurrentRcLock) {
-                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
-                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
-
-                    mCurrentRcClientGen++;
-                    // synchronously update the displays and clients with
-                    //      the new client generation
-                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                            rcse.mMediaIntent /*newMediaIntent*/,
-                            false /*clearing*/);
-
-                    // tell the current client that it needs to send info
-                    try {
-                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Current valid remote client is dead: "+e);
-                        mCurrentRcClient = null;
-                    }
-                } else {
-                    // the remote control display owner has changed between the
-                    // the message to update the display was sent, and the time it
-                    // gets to be processed (now)
-                }
-            }
-        }
-    }
-
-
-    /**
-     * Helper function:
-     * Called synchronized on mRCStack
-     */
-    private void clearRemoteControlDisplay_syncAfRcs() {
-        synchronized(mCurrentRcLock) {
-            mCurrentRcClient = null;
-        }
-        // will cause onRcDisplayClear() to be called in AudioService's handler thread
-        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
-    }
-
-    /**
-     * Helper function for code readability: only to be called from
-     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
-     *    this method.
-     * Preconditions:
-     *    - called synchronized mAudioFocusLock then on mRCStack
-     *    - mRCStack.isEmpty() is false
-     */
-    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
-        RemoteControlStackEntry rcse = mRCStack.peek();
-        int infoFlagsAboutToBeUsed = infoChangedFlags;
-        // this is where we enforce opt-in for information display on the remote controls
-        //   with the new AudioManager.registerRemoteControlClient() API
-        if (rcse.mRcClient == null) {
-            //Log.w(TAG, "Can't update remote control display with null remote control client");
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-        synchronized(mCurrentRcLock) {
-            if (!rcse.mRcClient.equals(mCurrentRcClient)) {
-                // new RC client, assume every type of information shall be queried
-                infoFlagsAboutToBeUsed = RC_INFO_ALL;
-            }
-            mCurrentRcClient = rcse.mRcClient;
-        }
-        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
-        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
-                infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) );
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mAudioFocusLock, then mRCStack
-     * Check whether the remote control display should be updated, triggers the update if required
-     * @param infoChangedFlags the flags corresponding to the remote control client information
-     *     that has changed, if applicable (checking for the update conditions might trigger a
-     *     clear, rather than an update event).
-     */
-    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
-        // determine whether the remote control display should be refreshed
-        // if either stack is empty, there is a mismatch, so clear the RC display
-        if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-
-        // determine which entry in the AudioFocus stack to consider, and compare against the
-        // top of the stack for the media button event receivers : simply using the top of the
-        // stack would make the entry disappear from the RemoteControlDisplay in conditions such as
-        // notifications playing during music playback.
-        // Crawl the AudioFocus stack from the top until an entry is found with the following
-        // characteristics:
-        // - focus gain on STREAM_MUSIC stream
-        // - non-transient focus gain on a stream other than music
-        FocusStackEntry af = null;
-        try {
-            for (int index = mFocusStack.size()-1; index >= 0; index--) {
-                FocusStackEntry fse = mFocusStack.elementAt(index);
-                if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
-                        || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) {
-                    af = fse;
-                    break;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
-            af = null;
-        }
-        if (af == null) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-
-        // if the audio focus and RC owners belong to different packages, there is a mismatch, clear
-        if ((mRCStack.peek().mCallingPackageName != null)
-                && (af.mPackageName != null)
-                && !(mRCStack.peek().mCallingPackageName.compareTo(
-                        af.mPackageName) == 0)) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-        // if the audio focus didn't originate from the same Uid as the one in which the remote
-        //   control information will be retrieved, clear
-        if (mRCStack.peek().mCallingUid != af.mCallingUid) {
-            clearRemoteControlDisplay_syncAfRcs();
-            return;
-        }
-
-        // refresh conditions were verified: update the remote controls
-        // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
-        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
-    }
-
-    /**
-     * Helper function:
-     * Post a message to asynchronously move the media button event receiver associated with the
-     * given remote control client ID to the top of the remote control stack
-     * @param rccId
-     */
-    private void postPromoteRcc(int rccId) {
-        sendMsg(mAudioHandler, MSG_PROMOTE_RCC, SENDMSG_REPLACE,
-                rccId /*arg1*/, 0, null, 0/*delay*/);
-    }
-
-    private void onPromoteRcc(int rccId) {
-        if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); }
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                // ignore if given RCC ID is already at top of remote control stack
-                if (!mRCStack.isEmpty() && (mRCStack.peek().mRccId == rccId)) {
-                    return;
-                }
-                int indexToPromote = -1;
-                try {
-                    for (int index = mRCStack.size()-1; index >= 0; index--) {
-                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                        if (rcse.mRccId == rccId) {
-                            indexToPromote = index;
-                            break;
-                        }
-                    }
-                    if (indexToPromote >= 0) {
-                        if (DEBUG_RC) { Log.d(TAG, "  moving RCC from index " + indexToPromote
-                                + " to " + (mRCStack.size()-1)); }
-                        final RemoteControlStackEntry rcse = mRCStack.remove(indexToPromote);
-                        mRCStack.push(rcse);
-                        // the RC stack changed, reevaluate the display
-                        checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                    }
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    // not expected to happen, indicates improper concurrent modification
-                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-                }
-            }//synchronized(mRCStack)
-        }//synchronized(mAudioFocusLock)
-    }
-
-    /**
-     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
-     * precondition: mediaIntent != null
-     */
-    public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
-            IBinder token) {
-        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
-
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token);
-                // new RC client, assume every type of information shall be queried
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
-        }
-    }
-
-    /**
-     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
-     * precondition: mediaIntent != null, eventReceiver != null
-     */
-    public void unregisterMediaButtonIntent(PendingIntent mediaIntent)
-    {
-        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
-
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
-                removeMediaButtonReceiver_syncAfRcs(mediaIntent);
-                if (topOfStackWillChange) {
-                    // current RC client will change, assume every type of info needs to be queried
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
-            }
-        }
-    }
-
-    /**
-     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
-     * precondition: c != null
-     */
-    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
-        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
-                != PackageManager.PERMISSION_GRANTED) {
-            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
-            return;
-        }
-        synchronized(mRCStack) {
-            mMediaReceiverForCalls = c;
-        }
-    }
-
-    /**
-     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
-     */
-    public void unregisterMediaButtonEventReceiverForCalls() {
-        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
-                != PackageManager.PERMISSION_GRANTED) {
-            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
-            return;
-        }
-        synchronized(mRCStack) {
-            mMediaReceiverForCalls = null;
-        }
-    }
-
-    /**
-     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
-     * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient
-     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
-     *     without modifying the RC stack, but while still causing the display to refresh (will
-     *     become blank as a result of this)
-     */
-    public int registerRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient, String callingPackageName) {
-        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                // store the new display information
-                try {
-                    for (int index = mRCStack.size()-1; index >= 0; index--) {
-                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                        if(rcse.mMediaIntent.equals(mediaIntent)) {
-                            // already had a remote control client?
-                            if (rcse.mRcClientDeathHandler != null) {
-                                // stop monitoring the old client's death
-                                rcse.unlinkToRcClientDeath();
-                            }
-                            // save the new remote control client
-                            rcse.mRcClient = rcClient;
-                            rcse.mCallingPackageName = callingPackageName;
-                            rcse.mCallingUid = Binder.getCallingUid();
-                            if (rcClient == null) {
-                                // here rcse.mRcClientDeathHandler is null;
-                                rcse.resetPlaybackInfo();
-                                break;
-                            }
-                            rccId = rcse.mRccId;
-
-                            // there is a new (non-null) client:
-                            // 1/ give the new client the displays (if any)
-                            if (mRcDisplays.size() > 0) {
-                                plugRemoteControlDisplaysIntoClient_syncRcStack(rcse.mRcClient);
-                            }
-                            // 2/ monitor the new client's death
-                            IBinder b = rcse.mRcClient.asBinder();
-                            RcClientDeathHandler rcdh =
-                                    new RcClientDeathHandler(b, rcse.mMediaIntent);
-                            try {
-                                b.linkToDeath(rcdh, 0);
-                            } catch (RemoteException e) {
-                                // remote control client is DOA, disqualify it
-                                Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
-                                rcse.mRcClient = null;
-                            }
-                            rcse.mRcClientDeathHandler = rcdh;
-                            break;
-                        }
-                    }//for
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    // not expected to happen, indicates improper concurrent modification
-                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-                }
-
-                // if the eventReceiver is at the top of the stack
-                // then check for potential refresh of the remote controls
-                if (isCurrentRcController(mediaIntent)) {
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
-            }//synchronized(mRCStack)
-        }//synchronized(mAudioFocusLock)
-        return rccId;
-    }
-
-    /**
-     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
-     * rcClient is guaranteed non-null
-     */
-    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient) {
-        if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                boolean topRccChange = false;
-                try {
-                    for (int index = mRCStack.size()-1; index >= 0; index--) {
-                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                        if ((rcse.mMediaIntent.equals(mediaIntent))
-                                && rcClient.equals(rcse.mRcClient)) {
-                            // we found the IRemoteControlClient to unregister
-                            // stop monitoring its death
-                            rcse.unlinkToRcClientDeath();
-                            // reset the client-related fields
-                            rcse.mRcClient = null;
-                            rcse.mCallingPackageName = null;
-                            topRccChange = (index == mRCStack.size()-1);
-                            // there can only be one matching RCC in the RC stack, we're done
-                            break;
-                        }
-                    }
-                } catch (ArrayIndexOutOfBoundsException e) {
-                    // not expected to happen, indicates improper concurrent modification
-                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-                }
-                if (topRccChange) {
-                    // no more RCC for the RCD, check for potential refresh of the remote controls
-                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-                }
-            }
-        }
-    }
-
-
-    /**
-     * A class to encapsulate all the information about a remote control display.
-     * After instanciation, init() must always be called before the object is added in the list
-     * of displays.
-     * Before being removed from the list of displays, release() must always be called (otherwise
-     * it will leak death handlers).
-     */
-    private class DisplayInfoForServer implements IBinder.DeathRecipient {
-        /** may never be null */
-        private IRemoteControlDisplay mRcDisplay;
-        private IBinder mRcDisplayBinder;
-        private int mArtworkExpectedWidth = -1;
-        private int mArtworkExpectedHeight = -1;
-        private boolean mWantsPositionSync = false;
-
-        public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
-            if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
-            mRcDisplay = rcd;
-            mRcDisplayBinder = rcd.asBinder();
-            mArtworkExpectedWidth = w;
-            mArtworkExpectedHeight = h;
-        }
-
-        public boolean init() {
-            try {
-                mRcDisplayBinder.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                // remote control display is DOA, disqualify it
-                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
-                return false;
-            }
-            return true;
-        }
-
-        public void release() {
-            try {
-                mRcDisplayBinder.unlinkToDeath(this, 0);
-            } catch (java.util.NoSuchElementException e) {
-                // not much we can do here, the display should have been unregistered anyway
-                Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
-            }
-        }
-
-        public void binderDied() {
-            synchronized(mRCStack) {
-                Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
-                // remove the display from the list
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                    if (di.mRcDisplay == mRcDisplay) {
-                        if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
-                        displayIterator.remove();
-                        return;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * The remote control displays.
-     * Access synchronized on mRCStack
-     */
-    private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
-
-    /**
-     * Plug each registered display into the specified client
-     * @param rcc, guaranteed non null
-     */
-    private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
-        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-        while (displayIterator.hasNext()) {
-            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-            try {
-                rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
-                        di.mArtworkExpectedHeight);
-                if (di.mWantsPositionSync) {
-                    rcc.setWantsSyncForDisplay(di.mRcDisplay, true);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
-            }
-        }
-    }
-
-    /**
-     * Is the remote control display interface already registered
-     * @param rcd
-     * @return true if the IRemoteControlDisplay is already in the list of displays
-     */
-    private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
-        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-        while (displayIterator.hasNext()) {
-            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-            if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Register an IRemoteControlDisplay.
-     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
-     * at the top of the stack to update the new display with its information.
-     * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
-     * @param rcd the IRemoteControlDisplay to register. No effect if null.
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     */
     public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
-        synchronized(mAudioFocusLock) {
-            synchronized(mRCStack) {
-                if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
-                    return;
-                }
-                DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
-                if (!di.init()) {
-                    if (DEBUG_RC) Log.e(TAG, " error registering RCD");
-                    return;
-                }
-                // add RCD to list of displays
-                mRcDisplays.add(di);
-
-                // let all the remote control clients know there is a new display (so the remote
-                //   control stack traversal order doesn't matter).
-                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-                while(stackIterator.hasNext()) {
-                    RemoteControlStackEntry rcse = stackIterator.next();
-                    if(rcse.mRcClient != null) {
-                        try {
-                            rcse.mRcClient.plugRemoteControlDisplay(rcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error connecting RCD to client: ", e);
-                        }
-                    }
-                }
-
-                // we have a new display, of which all the clients are now aware: have it be updated
-                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
-            }
-        }
+        mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
     }
 
-    /**
-     * Unregister an IRemoteControlDisplay.
-     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
-     * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
-     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
-     */
     public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
-        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
-        synchronized(mRCStack) {
-            if (rcd == null) {
-                return;
-            }
-
-            boolean displayWasPluggedIn = false;
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext() && !displayWasPluggedIn) {
-                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    displayWasPluggedIn = true;
-                    di.release();
-                    displayIterator.remove();
-                }
-            }
-
-            if (displayWasPluggedIn) {
-                // disconnect this remote control display from all the clients, so the remote
-                //   control stack traversal order doesn't matter
-                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-                while(stackIterator.hasNext()) {
-                    final RemoteControlStackEntry rcse = stackIterator.next();
-                    if(rcse.mRcClient != null) {
-                        try {
-                            rcse.mRcClient.unplugRemoteControlDisplay(rcd);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error disconnecting remote control display to client: ", e);
-                        }
-                    }
-                }
-            } else {
-                if (DEBUG_RC) Log.w(TAG, "  trying to unregister unregistered RCD");
-            }
-        }
+        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
     }
 
-    /**
-     * Update the size of the artwork used by an IRemoteControlDisplay.
-     * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
-     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     */
     public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
-        synchronized(mRCStack) {
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            boolean artworkSizeUpdate = false;
-            while (displayIterator.hasNext() && !artworkSizeUpdate) {
-                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
-                        di.mArtworkExpectedWidth = w;
-                        di.mArtworkExpectedHeight = h;
-                        artworkSizeUpdate = true;
-                    }
-                }
-            }
-            if (artworkSizeUpdate) {
-                // RCD is currently plugged in and its artwork size has changed, notify all RCCs,
-                // stack traversal order doesn't matter
-                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-                while(stackIterator.hasNext()) {
-                    final RemoteControlStackEntry rcse = stackIterator.next();
-                    if(rcse.mRcClient != null) {
-                        try {
-                            rcse.mRcClient.setBitmapSizeForDisplay(rcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
-                        }
-                    }
-                }
-            }
-        }
+        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
     }
 
-    /**
-     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
-     * playback position to verify that the estimated position has not drifted from the actual
-     * position. By default the check is not performed.
-     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
-     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
-     *     or disabled. Not null.
-     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
-     *     to the framework will regularly compare the estimated playback position with the actual
-     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
-     *     detected.
-     */
     public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
             boolean wantsSync) {
-        synchronized(mRCStack) {
-            boolean rcdRegistered = false;
-            // store the information about this display
-            // (display stack traversal order doesn't matter).
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    di.mWantsPositionSync = wantsSync;
-                    rcdRegistered = true;
-                    break;
-                }
-            }
-            if (!rcdRegistered) {
-                return;
-            }
-            // notify all current RemoteControlClients
-            // (stack traversal order doesn't matter as we notify all RCCs)
-            final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while (stackIterator.hasNext()) {
-                final RemoteControlStackEntry rcse = stackIterator.next();
-                if (rcse.mRcClient != null) {
-                    try {
-                        rcse.mRcClient.setWantsSyncForDisplay(rcd, wantsSync);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e);
-                    }
-                }
-            }
-        }
+        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
+    }
+
+    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
+        mMediaFocusControl.registerMediaButtonEventReceiverForCalls(c);
+    }
+
+    public void unregisterMediaButtonEventReceiverForCalls() {
+        mMediaFocusControl.unregisterMediaButtonEventReceiverForCalls();
+    }
+
+    public void registerMediaButtonIntent(PendingIntent pi, ComponentName c, IBinder token) {
+        mMediaFocusControl.registerMediaButtonIntent(pi, c, token);
+    }
+
+    public void unregisterMediaButtonIntent(PendingIntent pi) {
+        mMediaFocusControl.unregisterMediaButtonIntent(pi);
+    }
+ 
+    public int registerRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient, String callingPckg) {
+        return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg);
+    }
+
+    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient) {
+        mMediaFocusControl.unregisterRemoteControlClient(mediaIntent, rcClient);
     }
 
     public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
-        // ignore position change requests if invalid generation ID
-        synchronized(mRCStack) {
-            synchronized(mCurrentRcLock) {
-                if (mCurrentRcClientGen != generationId) {
-                    return;
-                }
-            }
-        }
-        // discard any unprocessed seek request in the message queue, and replace with latest
-        sendMsg(mAudioHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */,
-                0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */);
-    }
-
-    public void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
-        if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId +
-                ", timeMs=" + timeMs + ")");
-        synchronized(mRCStack) {
-            synchronized(mCurrentRcLock) {
-                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) {
-                    // tell the current client to seek to the requested location
-                    try {
-                        mCurrentRcClient.seekTo(generationId, timeMs);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Current valid remote client is dead: "+e);
-                        mCurrentRcClient = null;
-                    }
-                }
-            }
-        }
-    }
-
-    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
-        sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
-                rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);
-    }
-
-    // handler for MSG_RCC_NEW_PLAYBACK_INFO
-    private void onNewPlaybackInfoForRcc(int rccId, int key, int value) {
-        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId +
-                ", what=" + key + ",val=" + value + ")");
-        synchronized(mRCStack) {
-            // iterating from top of stack as playback information changes are more likely
-            //   on entries at the top of the remote control stack
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    if (rcse.mRccId == rccId) {
-                        switch (key) {
-                            case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE:
-                                rcse.mPlaybackType = value;
-                                postReevaluateRemote();
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_VOLUME:
-                                rcse.mPlaybackVolume = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemote.mVolume = value;
-                                        mVolumePanel.postHasNewRemotePlaybackInfo();
-                                    }
-                                }
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX:
-                                rcse.mPlaybackVolumeMax = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemote.mVolumeMax = value;
-                                        mVolumePanel.postHasNewRemotePlaybackInfo();
-                                    }
-                                }
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING:
-                                rcse.mPlaybackVolumeHandling = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemote.mVolumeHandling = value;
-                                        mVolumePanel.postHasNewRemotePlaybackInfo();
-                                    }
-                                }
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
-                                rcse.mPlaybackStream = value;
-                                break;
-                            default:
-                                Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
-                                break;
-                        }
-                        return;
-                    }
-                }//for
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index mRCStack on onNewPlaybackInfoForRcc, lock error? ", e);
-            }
-        }
-    }
-
-    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
-        sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE,
-                rccId /* arg1 */, state /* arg2 */,
-                new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */);
-    }
-
-    public void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) {
-        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
-                + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
-        synchronized(mRCStack) {
-            // iterating from top of stack as playback information changes are more likely
-            //   on entries at the top of the remote control stack
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    if (rcse.mRccId == rccId) {
-                        rcse.mPlaybackState = newState;
-                        synchronized (mMainRemote) {
-                            if (rccId == mMainRemote.mRccId) {
-                                mMainRemoteIsActive = isPlaystateActive(state);
-                                postReevaluateRemote();
-                            }
-                        }
-                        // an RCC moving to a "playing" state should become the media button
-                        //   event receiver so it can be controlled, without requiring the
-                        //   app to re-register its receiver
-                        if (isPlaystateActive(state)) {
-                            postPromoteRcc(rccId);
-                        }
-                    }
-                }//for
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index on mRCStack in onNewPlaybackStateForRcc, lock error? ", e);
-            }
-        }
+        mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
     }
 
     public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
-        sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE,
-                rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */);
-    }
-
-    // handler for MSG_RCC_NEW_VOLUME_OBS
-    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
-        synchronized(mRCStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    if (rcse.mRccId == rccId) {
-                        rcse.mRemoteVolumeObs = rvo;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-    }
-
-    /**
-     * Checks if a remote client is active on the supplied stream type. Update the remote stream
-     * volume state if found and playing
-     * @param streamType
-     * @return false if no remote playing is currently playing
-     */
-    private boolean checkUpdateRemoteStateIfActive(int streamType) {
-        synchronized(mRCStack) {
-            // iterating from top of stack as active playback is more likely on entries at the top
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
-                            && isPlaystateActive(rcse.mPlaybackState.mState)
-                            && (rcse.mPlaybackStream == streamType)) {
-                        if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
-                                + ", vol =" + rcse.mPlaybackVolume);
-                        synchronized (mMainRemote) {
-                            mMainRemote.mRccId = rcse.mRccId;
-                            mMainRemote.mVolume = rcse.mPlaybackVolume;
-                            mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax;
-                            mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling;
-                            mMainRemoteIsActive = true;
-                        }
-                        return true;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-            }
-        }
-        synchronized (mMainRemote) {
-            mMainRemoteIsActive = false;
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if the given playback state is considered "active", i.e. it describes a state
-     * where playback is happening, or about to
-     * @param playState the playback state to evaluate
-     * @return true if active, false otherwise (inactive or unknown)
-     */
-    private static boolean isPlaystateActive(int playState) {
-        switch (playState) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    private void adjustRemoteVolume(int streamType, int direction, int flags) {
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        boolean volFixed = false;
-        synchronized (mMainRemote) {
-            if (!mMainRemoteIsActive) {
-                if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client");
-                return;
-            }
-            rccId = mMainRemote.mRccId;
-            volFixed = (mMainRemote.mVolumeHandling ==
-                    RemoteControlClient.PLAYBACK_VOLUME_FIXED);
-        }
-        // unlike "local" stream volumes, we can't compute the new volume based on the direction,
-        // we can only notify the remote that volume needs to be updated, and we'll get an async'
-        // update through setPlaybackInfoForRcc()
-        if (!volFixed) {
-            sendVolumeUpdateToRemote(rccId, direction);
-        }
-
-        // fire up the UI
-        mVolumePanel.postRemoteVolumeChanged(streamType, flags);
-    }
-
-    private void sendVolumeUpdateToRemote(int rccId, int direction) {
-        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
-        if (direction == 0) {
-            // only handling discrete events
-            return;
-        }
-        IRemoteVolumeObserver rvo = null;
-        synchronized (mRCStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    if (rcse.mRccId == rccId) {
-                        rvo = rcse.mRemoteVolumeObs;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-        if (rvo != null) {
-            try {
-                rvo.dispatchRemoteVolumeUpdate(direction, -1);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error dispatching relative volume update", e);
-            }
-        }
-    }
-
-    public int getRemoteStreamMaxVolume() {
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return 0;
-            }
-            return mMainRemote.mVolumeMax;
-        }
+        mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo);
     }
 
     public int getRemoteStreamVolume() {
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return 0;
-            }
-            return mMainRemote.mVolume;
-        }
+        return mMediaFocusControl.getRemoteStreamVolume();
     }
 
-    public void setRemoteStreamVolume(int vol) {
-        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return;
-            }
-            rccId = mMainRemote.mRccId;
-        }
-        IRemoteVolumeObserver rvo = null;
-        synchronized (mRCStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mRCStack.size()-1; index >= 0; index--) {
-                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
-                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    if (rcse.mRccId == rccId) {
-                        rvo = rcse.mRemoteVolumeObs;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-        if (rvo != null) {
-            try {
-                rvo.dispatchRemoteVolumeUpdate(0, vol);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error dispatching absolute volume update", e);
-            }
-        }
+    public int getRemoteStreamMaxVolume() {
+        return mMediaFocusControl.getRemoteStreamMaxVolume();
     }
 
-    /**
-     * Call to make AudioService reevaluate whether it's in a mode where remote players should
-     * have their volume controlled. In this implementation this is only to reset whether
-     * VolumePanel should display remote volumes
-     */
-    private void postReevaluateRemote() {
-        sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
+    public void setRemoteStreamVolume(int index) {
+        mMediaFocusControl.setRemoteStreamVolume(index);
     }
 
-    private void onReevaluateRemote() {
-        if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); }
-        // is there a registered RemoteControlClient that is handling remote playback
-        boolean hasRemotePlayback = false;
-        synchronized (mRCStack) {
-            // iteration stops when PLAYBACK_TYPE_REMOTE is found, so remote control stack
-            //   traversal order doesn't matter
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
-                    hasRemotePlayback = true;
-                    break;
-                }
-            }
-        }
-        synchronized (mMainRemote) {
-            if (mHasRemotePlayback != hasRemotePlayback) {
-                mHasRemotePlayback = hasRemotePlayback;
-                mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback);
-            }
-        }
+    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
+        mMediaFocusControl.setPlaybackStateForRcc(rccId, state, timeMs, speed);
+    }
+
+    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
+        mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value);
+    }
+
+    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+        mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+    }
+
+    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
+        mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+    }
+
+    //==========================================================================================
+    // Audio Focus
+    //==========================================================================================
+    public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
+        return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
+                clientId, callingPackageName);
+    }
+
+    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
+        return mMediaFocusControl.abandonAudioFocus(fd, clientId);
+    }
+
+    public void unregisterAudioFocusClient(String clientId) {
+        mMediaFocusControl.unregisterAudioFocusClient(clientId);
     }
 
     //==========================================================================================
@@ -6688,14 +4499,20 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
 
-        dumpFocusStack(pw);
-        dumpRCStack(pw);
-        dumpRCCStack(pw);
-        dumpRCDList(pw);
+        mMediaFocusControl.dump(pw);
         dumpStreamStates(pw);
         dumpRingerMode(pw);
         pw.println("\nAudio routes:");
         pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
         pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
     }
+
+    // Inform AudioFlinger of our device's low RAM attribute
+    private static void readAndSetLowRamDevice()
+    {
+        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
+        if (status != 0) {
+            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
+        }
+    }
 }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index d42bfd44..4805da5 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -403,4 +403,6 @@
     public static native int getPrimaryOutputFrameCount();
     public static native int getOutputLatency(int stream);
 
+    public static native int setLowRamDevice(boolean isLowRamDevice);
+
 }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index e60ecc4..4a1646b 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -112,10 +112,10 @@
 
     oneway void setRemoteSubmixOn(boolean on, int address);
 
-    int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l,
-            String clientId, String callingPackageName);
+    int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName);
 
-    int abandonAudioFocus(IAudioFocusDispatcher l, String clientId);
+    int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId);
     
     void unregisterAudioFocusClient(String clientId);
 
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
new file mode 100644
index 0000000..e56baef
--- /dev/null
+++ b/media/java/android/media/MediaFocusControl.java
@@ -0,0 +1,2455 @@
+/*
+ * 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.Activity;
+import android.app.AppOpsManager;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.app.PendingIntent.OnFinished;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.IBinder.DeathRecipient;
+import android.provider.Settings;
+import android.speech.RecognizerIntent;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Stack;
+
+/**
+ * @hide
+ *
+ */
+public class MediaFocusControl implements OnFinished {
+
+    private static final String TAG = "MediaFocusControl";
+
+    /** Debug remote control client/display feature */
+    protected static final boolean DEBUG_RC = false;
+    /** Debug volumes */
+    protected static final boolean DEBUG_VOL = false;
+
+    /** Used to alter media button redirection when the phone is ringing. */
+    private boolean mIsRinging = false;
+
+    private final PowerManager.WakeLock mMediaEventWakeLock;
+    private final MediaEventHandler mEventHandler;
+    private final Context mContext;
+    private final ContentResolver mContentResolver;
+    private final VolumeController mVolumeController;
+    private final BroadcastReceiver mReceiver = new PackageIntentsReceiver();
+    private final AppOpsManager mAppOps;
+    private final KeyguardManager mKeyguardManager;
+    private final AudioService mAudioService;
+
+    protected MediaFocusControl(Looper looper, Context cntxt,
+            VolumeController volumeCtrl, AudioService as) {
+        mEventHandler = new MediaEventHandler(looper);
+        mContext = cntxt;
+        mContentResolver = mContext.getContentResolver();
+        mVolumeController = volumeCtrl;
+        mAudioService = as;
+
+        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+        mMainRemote = new RemotePlaybackState(-1,
+                AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC),
+                AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC));
+
+        // Register for phone state monitoring
+        TelephonyManager tmgr = (TelephonyManager)
+                mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+        // Register for package addition/removal/change intent broadcasts
+        //    for media button receiver persistence
+        IntentFilter pkgFilter = new IntentFilter();
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+        pkgFilter.addDataScheme("package");
+        mContext.registerReceiver(mReceiver, pkgFilter);
+
+        mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mKeyguardManager =
+                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+
+        mHasRemotePlayback = false;
+        mMainRemoteIsActive = false;
+        postReevaluateRemote();
+    }
+
+    // event handler messages
+    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 0;
+    private static final int MSG_RCDISPLAY_CLEAR = 1;
+    private static final int MSG_RCDISPLAY_UPDATE = 2;
+    private static final int MSG_REEVALUATE_REMOTE = 3;
+    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 4;
+    private static final int MSG_RCC_NEW_VOLUME_OBS = 5;
+    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;
+
+    // sendMsg() flags
+    /** 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 delay) {
+
+        if (existingMsgPolicy == SENDMSG_REPLACE) {
+            handler.removeMessages(msg);
+        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+            return;
+        }
+
+        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
+    }
+
+    private class MediaEventHandler extends Handler {
+        MediaEventHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_PERSIST_MEDIABUTTONRECEIVER:
+                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
+                    break;
+
+                case MSG_RCDISPLAY_CLEAR:
+                    onRcDisplayClear();
+                    break;
+
+                case MSG_RCDISPLAY_UPDATE:
+                    // msg.obj is guaranteed to be non null
+                    onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1);
+                    break;
+
+                case MSG_REEVALUATE_REMOTE:
+                    onReevaluateRemote();
+                    break;
+
+                case MSG_RCC_NEW_PLAYBACK_INFO:
+                    onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */,
+                            ((Integer)msg.obj).intValue() /* value */);
+                    break;
+                case MSG_RCC_NEW_VOLUME_OBS:
+                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
+                            (IRemoteVolumeObserver)msg.obj /* rvo */);
+                    break;
+                case MSG_RCC_NEW_PLAYBACK_STATE:
+                    onNewPlaybackStateForRcc(msg.arg1 /* rccId */,
+                            msg.arg2 /* state */,
+                            (RccPlaybackState)msg.obj /* newState */);
+                    break;
+                case MSG_RCC_SEEK_REQUEST:
+                    onSetRemoteControlClientPlaybackPosition(
+                            msg.arg1 /* generationId */, ((Long)msg.obj).longValue() /* timeMs */);
+
+                case MSG_PROMOTE_RCC:
+                    onPromoteRcc(msg.arg1);
+                    break;
+            }
+        }
+    }
+
+    protected void dump(PrintWriter pw) {
+        dumpFocusStack(pw);
+        dumpRCStack(pw);
+        dumpRCCStack(pw);
+        dumpRCDList(pw);
+    }
+
+    private class PackageIntentsReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
+                    || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
+                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    // a package is being removed, not replaced
+                    String packageName = intent.getData().getSchemeSpecificPart();
+                    if (packageName != null) {
+                        cleanupMediaButtonReceiverForPackage(packageName, true);
+                    }
+                }
+            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
+                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
+                String packageName = intent.getData().getSchemeSpecificPart();
+                if (packageName != null) {
+                    cleanupMediaButtonReceiverForPackage(packageName, false);
+                }
+            }
+        }
+    }
+
+    //==========================================================================================
+    // AudioFocus
+    //==========================================================================================
+
+    /* constant to identify focus stack entry that is used to hold the focus while the phone
+     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
+     * entering and exiting calls.
+     */
+    protected final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
+
+    private final static Object mAudioFocusLock = new Object();
+
+    private final static Object mRingingLock = new Object();
+
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onCallStateChanged(int state, String incomingNumber) {
+            if (state == TelephonyManager.CALL_STATE_RINGING) {
+                //Log.v(TAG, " CALL_STATE_RINGING");
+                synchronized(mRingingLock) {
+                    mIsRinging = true;
+                }
+            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
+                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
+                synchronized(mRingingLock) {
+                    mIsRinging = false;
+                }
+            }
+        }
+    };
+
+    /**
+     * Discard the current audio focus owner.
+     * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
+     * focus), remove it from the stack, and clear the remote control display.
+     */
+    protected void discardAudioFocusOwner() {
+        synchronized(mAudioFocusLock) {
+            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+                // notify the current focus owner it lost focus after removing it from stack
+                FocusStackEntry focusOwner = mFocusStack.pop();
+                try {
+                    focusOwner.mFocusDispatcher.dispatchAudioFocusChange(
+                            AudioManager.AUDIOFOCUS_LOSS, focusOwner.mClientId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failure to signal loss of audio focus due to "+ e);
+                    e.printStackTrace();
+                }
+                focusOwner.unlinkToDeath();
+                // clear RCD
+                synchronized(mRCStack) {
+                    clearRemoteControlDisplay_syncAfRcs();
+                }
+            }
+        }
+    }
+
+    private void notifyTopOfAudioFocusStack() {
+        // notify the top of the stack it gained focus
+        if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+            if (canReassignAudioFocus()) {
+                try {
+                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
+                            AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private static class FocusStackEntry {
+        public int mStreamType = -1;// no stream type
+        public IAudioFocusDispatcher mFocusDispatcher = null;
+        public IBinder mSourceRef = null;
+        public String mClientId;
+        public int mFocusChangeType;
+        public AudioFocusDeathHandler mHandler;
+        public String mPackageName;
+        public int mCallingUid;
+
+        public FocusStackEntry() {
+        }
+
+        public FocusStackEntry(int streamType, int duration,
+                IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
+                String pn, int uid) {
+            mStreamType = streamType;
+            mFocusDispatcher = afl;
+            mSourceRef = source;
+            mClientId = id;
+            mFocusChangeType = duration;
+            mHandler = hdlr;
+            mPackageName = pn;
+            mCallingUid = uid;
+        }
+
+        public void unlinkToDeath() {
+            try {
+                if (mSourceRef != null && mHandler != null) {
+                    mSourceRef.unlinkToDeath(mHandler, 0);
+                    mHandler = null;
+                }
+            } catch (java.util.NoSuchElementException e) {
+                Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()");
+            }
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            unlinkToDeath(); // unlink exception handled inside method
+            super.finalize();
+        }
+    }
+
+    private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the audio focus stack
+     */
+    private void dumpFocusStack(PrintWriter pw) {
+        pw.println("\nAudio Focus stack entries (last is top of stack):");
+        synchronized(mAudioFocusLock) {
+            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
+            while(stackIterator.hasNext()) {
+                FocusStackEntry fse = stackIterator.next();
+                pw.println("  source:" + fse.mSourceRef
+                        + " -- pack: " + fse.mPackageName
+                        + " -- client: " + fse.mClientId
+                        + " -- duration: " + fse.mFocusChangeType
+                        + " -- uid: " + fse.mCallingUid
+                        + " -- stream: " + fse.mStreamType);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mAudioFocusLock
+     * Remove a focus listener from the focus stack.
+     * @param clientToRemove the focus listener
+     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
+     *   focus, notify the next item in the stack it gained focus.
+     */
+    private void removeFocusStackEntry(String clientToRemove, boolean signal) {
+        // is the current top of the focus stack abandoning focus? (because of request, not death)
+        if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
+        {
+            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
+            FocusStackEntry fse = mFocusStack.pop();
+            fse.unlinkToDeath();
+            if (signal) {
+                // notify the new top of the stack it gained focus
+                notifyTopOfAudioFocusStack();
+                // there's a new top of the stack, let the remote control know
+                synchronized(mRCStack) {
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                }
+            }
+        } else {
+            // focus is abandoned by a client that's not at the top of the stack,
+            // no need to update focus.
+            // (using an iterator on the stack so we can safely remove an entry after having
+            //  evaluated it, traversal order doesn't matter here)
+            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
+            while(stackIterator.hasNext()) {
+                FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
+                if(fse.mClientId.equals(clientToRemove)) {
+                    Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
+                            + fse.mClientId);
+                    stackIterator.remove();
+                    fse.unlinkToDeath();
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mAudioFocusLock
+     * Remove focus listeners from the focus stack for a particular client when it has died.
+     */
+    private void removeFocusStackEntryForClient(IBinder cb) {
+        // is the owner of the audio focus part of the client to remove?
+        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
+                mFocusStack.peek().mSourceRef.equals(cb);
+        // (using an iterator on the stack so we can safely remove an entry after having
+        //  evaluated it, traversal order doesn't matter here)
+        Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
+        while(stackIterator.hasNext()) {
+            FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
+            if(fse.mSourceRef.equals(cb)) {
+                Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
+                        + fse.mClientId);
+                stackIterator.remove();
+                // the client just died, no need to unlink to its death
+            }
+        }
+        if (isTopOfStackForClientToRemove) {
+            // we removed an entry at the top of the stack:
+            //  notify the new top of the stack it gained focus.
+            notifyTopOfAudioFocusStack();
+            // there's a new top of the stack, let the remote control know
+            synchronized(mRCStack) {
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
+     */
+    private boolean canReassignAudioFocus() {
+        // focus requests are rejected during a phone call or when the phone is ringing
+        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
+        if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
+     * stack if necessary.
+     */
+    private class AudioFocusDeathHandler implements IBinder.DeathRecipient {
+        private IBinder mCb; // To be notified of client's death
+
+        AudioFocusDeathHandler(IBinder cb) {
+            mCb = cb;
+        }
+
+        public void binderDied() {
+            synchronized(mAudioFocusLock) {
+                Log.w(TAG, "  AudioFocus   audio focus client died");
+                removeFocusStackEntryForClient(mCb);
+            }
+        }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
+    }
+
+
+    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int)  */
+    protected int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
+        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
+        // the main stream type for the audio focus request is currently not used. It may
+        // potentially be used to handle multiple stream type-dependent audio focuses.
+
+        // we need a valid binder callback for clients
+        if (!cb.pingBinder()) {
+            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
+            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        }
+
+        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
+                callingPackageName) != AppOpsManager.MODE_ALLOWED) {
+            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        }
+
+        synchronized(mAudioFocusLock) {
+            if (!canReassignAudioFocus()) {
+                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+
+            // handle the potential premature death of the new holder of the focus
+            // (premature death == death before abandoning focus)
+            // Register for client death notification
+            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
+            try {
+                cb.linkToDeath(afdh, 0);
+            } catch (RemoteException e) {
+                // client has already died!
+                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
+                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+
+            if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
+                // if focus is already owned by this client and the reason for acquiring the focus
+                // hasn't changed, don't do anything
+                if (mFocusStack.peek().mFocusChangeType == focusChangeHint) {
+                    // unlink death handler so it can be gc'ed.
+                    // linkToDeath() creates a JNI global reference preventing collection.
+                    cb.unlinkToDeath(afdh, 0);
+                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+                }
+                // the reason for the audio focus request has changed: remove the current top of
+                // stack and respond as if we had a new focus owner
+                FocusStackEntry fse = mFocusStack.pop();
+                fse.unlinkToDeath();
+            }
+
+            // notify current top of stack it is losing focus
+            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+                try {
+                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
+                            -1 * focusChangeHint, // loss and gain codes are inverse of each other
+                            mFocusStack.peek().mClientId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, " Failure to signal loss of focus due to "+ e);
+                    e.printStackTrace();
+                }
+            }
+
+            // focus requester might already be somewhere below in the stack, remove it
+            removeFocusStackEntry(clientId, false /* signal */);
+
+            // push focus requester at the top of the audio focus stack
+            mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
+                    clientId, afdh, callingPackageName, Binder.getCallingUid()));
+
+            // there's a new top of the stack, let the remote control know
+            synchronized(mRCStack) {
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+            }
+        }//synchronized(mAudioFocusLock)
+
+        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+    }
+
+    /** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener)  */
+    protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
+        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
+        try {
+            // this will take care of notifying the new focus owner if needed
+            synchronized(mAudioFocusLock) {
+                removeFocusStackEntry(clientId, true);
+            }
+        } catch (java.util.ConcurrentModificationException cme) {
+            // Catching this exception here is temporary. It is here just to prevent
+            // a crash seen when the "Silent" notification is played. This is believed to be fixed
+            // but this try catch block is left just to be safe.
+            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
+            cme.printStackTrace();
+        }
+
+        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+    }
+
+
+    protected void unregisterAudioFocusClient(String clientId) {
+        synchronized(mAudioFocusLock) {
+            removeFocusStackEntry(clientId, false);
+        }
+    }
+
+
+    //==========================================================================================
+    // RemoteControl
+    //==========================================================================================
+    protected void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
+    }
+
+    protected void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
+        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
+    }
+
+    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        // sanity check on the incoming key event
+        if (!isValidMediaKeyEvent(keyEvent)) {
+            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
+            return;
+        }
+        // event filtering for telephony
+        synchronized(mRingingLock) {
+            synchronized(mRCStack) {
+                if ((mMediaReceiverForCalls != null) &&
+                        (mIsRinging || (mAudioService.getMode() == AudioSystem.MODE_IN_CALL))) {
+                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
+                    return;
+                }
+            }
+        }
+        // event filtering based on voice-based interactions
+        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
+            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
+        } else {
+            dispatchMediaKeyEvent(keyEvent, needWakeLock);
+        }
+    }
+
+    /**
+     * Handles the dispatching of the media button events to the telephony package.
+     * Precondition: mMediaReceiverForCalls != null
+     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
+        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
+        }
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+                    null, mKeyEventDone, mEventHandler, Activity.RESULT_OK, null, null);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    /**
+     * Handles the dispatching of the media button events to one of the registered listeners,
+     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
+     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+        }
+        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+        synchronized(mRCStack) {
+            if (!mRCStack.empty()) {
+                // send the intent that was registered by the client
+                try {
+                    mRCStack.peek().mMediaIntent.send(mContext,
+                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
+                            keyIntent, this, mEventHandler);
+                } catch (CanceledException e) {
+                    Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
+                    e.printStackTrace();
+                }
+            } else {
+                // legacy behavior when nobody registered their media button event receiver
+                //    through AudioManager
+                if (needWakeLock) {
+                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
+                }
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+                            null, mKeyEventDone,
+                            mEventHandler, Activity.RESULT_OK, null, null);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+    }
+
+    /**
+     * The different actions performed in response to a voice button key event.
+     */
+    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
+    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
+    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
+
+    private final Object mVoiceEventLock = new Object();
+    private boolean mVoiceButtonDown;
+    private boolean mVoiceButtonHandled;
+
+    /**
+     * Filter key events that may be used for voice-based interactions
+     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
+     *    media buttons that can be used to trigger voice-based interactions.
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        if (DEBUG_RC) {
+            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
+        }
+
+        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
+        int keyAction = keyEvent.getAction();
+        synchronized (mVoiceEventLock) {
+            if (keyAction == KeyEvent.ACTION_DOWN) {
+                if (keyEvent.getRepeatCount() == 0) {
+                    // initial down
+                    mVoiceButtonDown = true;
+                    mVoiceButtonHandled = false;
+                } else if (mVoiceButtonDown && !mVoiceButtonHandled
+                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                    // long-press, start voice-based interactions
+                    mVoiceButtonHandled = true;
+                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
+                }
+            } else if (keyAction == KeyEvent.ACTION_UP) {
+                if (mVoiceButtonDown) {
+                    // voice button up
+                    mVoiceButtonDown = false;
+                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
+                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
+                    }
+                }
+            }
+        }//synchronized (mVoiceEventLock)
+
+        // take action after media button event filtering for voice-based interactions
+        switch (voiceButtonAction) {
+            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
+                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
+                break;
+            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
+                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
+                // then start the voice-based interactions
+                startVoiceBasedInteractions(needWakeLock);
+                break;
+            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
+                if (DEBUG_RC) Log.v(TAG, "   send simulated key event, wakelock=" + needWakeLock);
+                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
+                break;
+        }
+    }
+
+    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
+        // send DOWN event
+        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
+        dispatchMediaKeyEvent(keyEvent, needWakeLock);
+        // send UP event
+        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
+        dispatchMediaKeyEvent(keyEvent, needWakeLock);
+
+    }
+
+
+    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
+        if (keyEvent == null) {
+            return false;
+        }
+        final int keyCode = keyEvent.getKeyCode();
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_CLOSE:
+            case KeyEvent.KEYCODE_MEDIA_EJECT:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
+                break;
+            default:
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Checks whether the given key code is one that can trigger the launch of voice-based
+     *   interactions.
+     * @param keyCode the key code associated with the key event
+     * @return true if the key is one of the supported voice-based interaction triggers
+     */
+    private static boolean isValidVoiceInputKeyCode(int keyCode) {
+        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Tell the system to start voice-based interactions / voice commands
+     */
+    private void startVoiceBasedInteractions(boolean needWakeLock) {
+        Intent voiceIntent = null;
+        // select which type of search to launch:
+        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
+        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
+        //    with EXTRA_SECURE set to true if the device is securely locked
+        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+        if (!isLocked && pm.isScreenOn()) {
+            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
+            Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
+        } else {
+            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
+                    isLocked && mKeyguardManager.isKeyguardSecure());
+            Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
+        }
+        // start the search activity
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (voiceIntent != null) {
+                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
+            }
+        } catch (ActivityNotFoundException e) {
+            Log.w(TAG, "No activity for search: " + e);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+            if (needWakeLock) {
+                mMediaEventWakeLock.release();
+            }
+        }
+    }
+
+    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
+
+    // only set when wakelock was acquired, no need to check value when received
+    private static final String EXTRA_WAKELOCK_ACQUIRED =
+            "android.media.AudioService.WAKELOCK_ACQUIRED";
+
+    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
+            int resultCode, String resultData, Bundle resultExtras) {
+        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
+            mMediaEventWakeLock.release();
+        }
+    }
+
+    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            if (intent == null) {
+                return;
+            }
+            Bundle extras = intent.getExtras();
+            if (extras == null) {
+                return;
+            }
+            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
+                mMediaEventWakeLock.release();
+            }
+        }
+    };
+
+    /**
+     * Synchronization on mCurrentRcLock always inside a block synchronized on mRCStack
+     */
+    private final Object mCurrentRcLock = new Object();
+    /**
+     * The one remote control client which will receive a request for display information.
+     * This object may be null.
+     * Access protected by mCurrentRcLock.
+     */
+    private IRemoteControlClient mCurrentRcClient = null;
+
+    private final static int RC_INFO_NONE = 0;
+    private final static int RC_INFO_ALL =
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
+
+    /**
+     * A monotonically increasing generation counter for mCurrentRcClient.
+     * Only accessed with a lock on mCurrentRcLock.
+     * No value wrap-around issues as we only act on equal values.
+     */
+    private int mCurrentRcClientGen = 0;
+
+    /**
+     * Inner class to monitor remote control client deaths, and remove the client for the
+     * remote control stack if necessary.
+     */
+    private class RcClientDeathHandler implements IBinder.DeathRecipient {
+        final private IBinder mCb; // To be notified of client's death
+        final private PendingIntent mMediaIntent;
+
+        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
+            mCb = cb;
+            mMediaIntent = pi;
+        }
+
+        public void binderDied() {
+            Log.w(TAG, "  RemoteControlClient died");
+            // remote control client died, make sure the displays don't use it anymore
+            //  by setting its remote control client to null
+            registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
+            // the dead client was maybe handling remote playback, reevaluate
+            postReevaluateRemote();
+        }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
+    }
+
+    /**
+     * A global counter for RemoteControlClient identifiers
+     */
+    private static int sLastRccId = 0;
+
+    private class RemotePlaybackState {
+        int mRccId;
+        int mVolume;
+        int mVolumeMax;
+        int mVolumeHandling;
+
+        private RemotePlaybackState(int id, int vol, int volMax) {
+            mRccId = id;
+            mVolume = vol;
+            mVolumeMax = volMax;
+            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
+        }
+    }
+
+    /**
+     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
+     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
+     * every time we need this info.
+     */
+    private RemotePlaybackState mMainRemote;
+    /**
+     * Indicates whether the "main" RemoteControlClient is considered active.
+     * Use synchronized on mMainRemote.
+     */
+    private boolean mMainRemoteIsActive;
+    /**
+     * Indicates whether there is remote playback going on. True even if there is no "active"
+     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
+     * handles remote playback.
+     * Use synchronized on mMainRemote.
+     */
+    private boolean mHasRemotePlayback;
+
+    private static class RccPlaybackState {
+        public int mState;
+        public long mPositionMs;
+        public float mSpeed;
+
+        public RccPlaybackState(int state, long positionMs, float speed) {
+            mState = state;
+            mPositionMs = positionMs;
+            mSpeed = speed;
+        }
+
+        public void reset() {
+            mState = RemoteControlClient.PLAYSTATE_STOPPED;
+            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
+            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
+        }
+
+        @Override
+        public String toString() {
+            return stateToString() + ", " + posToString() + ", " + mSpeed + "X";
+        }
+
+        private String posToString() {
+            if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) {
+                return "PLAYBACK_POSITION_INVALID";
+            } else if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
+                return "PLAYBACK_POSITION_ALWAYS_UNKNOWN";
+            } else {
+                return (String.valueOf(mPositionMs) + "ms");
+            }
+        }
+
+        private String stateToString() {
+            switch (mState) {
+                case RemoteControlClient.PLAYSTATE_NONE:
+                    return "PLAYSTATE_NONE";
+                case RemoteControlClient.PLAYSTATE_STOPPED:
+                    return "PLAYSTATE_STOPPED";
+                case RemoteControlClient.PLAYSTATE_PAUSED:
+                    return "PLAYSTATE_PAUSED";
+                case RemoteControlClient.PLAYSTATE_PLAYING:
+                    return "PLAYSTATE_PLAYING";
+                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+                    return "PLAYSTATE_FAST_FORWARDING";
+                case RemoteControlClient.PLAYSTATE_REWINDING:
+                    return "PLAYSTATE_REWINDING";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                    return "PLAYSTATE_SKIPPING_FORWARDS";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+                    return "PLAYSTATE_SKIPPING_BACKWARDS";
+                case RemoteControlClient.PLAYSTATE_BUFFERING:
+                    return "PLAYSTATE_BUFFERING";
+                case RemoteControlClient.PLAYSTATE_ERROR:
+                    return "PLAYSTATE_ERROR";
+                default:
+                    return "[invalid playstate]";
+            }
+        }
+    }
+
+    protected static class RemoteControlStackEntry implements DeathRecipient {
+        public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        final public MediaFocusControl mController;
+        /**
+         * The target for the ACTION_MEDIA_BUTTON events.
+         * Always non null.
+         */
+        final public PendingIntent mMediaIntent;
+        /**
+         * The registered media button event receiver.
+         * Always non null.
+         */
+        final public ComponentName mReceiverComponent;
+        public IBinder mToken;
+        public String mCallingPackageName;
+        public int mCallingUid;
+        /**
+         * Provides access to the information to display on the remote control.
+         * May be null (when a media button event receiver is registered,
+         *     but no remote control client has been registered) */
+        public IRemoteControlClient mRcClient;
+        public RcClientDeathHandler mRcClientDeathHandler;
+        /**
+         * Information only used for non-local playback
+         */
+        public int mPlaybackType;
+        public int mPlaybackVolume;
+        public int mPlaybackVolumeMax;
+        public int mPlaybackVolumeHandling;
+        public int mPlaybackStream;
+        public RccPlaybackState mPlaybackState;
+        public IRemoteVolumeObserver mRemoteVolumeObs;
+
+        public void resetPlaybackInfo() {
+            mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
+            mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
+            mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
+            mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
+            mPlaybackStream = AudioManager.STREAM_MUSIC;
+            mPlaybackState.reset();
+            mRemoteVolumeObs = null;
+        }
+
+        /** precondition: mediaIntent != null */
+        public RemoteControlStackEntry(MediaFocusControl controller, PendingIntent mediaIntent,
+                ComponentName eventReceiver, IBinder token) {
+            mController = controller;
+            mMediaIntent = mediaIntent;
+            mReceiverComponent = eventReceiver;
+            mToken = token;
+            mCallingUid = -1;
+            mRcClient = null;
+            mRccId = ++sLastRccId;
+            mPlaybackState = new RccPlaybackState(
+                    RemoteControlClient.PLAYSTATE_STOPPED,
+                    RemoteControlClient.PLAYBACK_POSITION_INVALID,
+                    RemoteControlClient.PLAYBACK_SPEED_1X);
+
+            resetPlaybackInfo();
+            if (mToken != null) {
+                try {
+                    mToken.linkToDeath(this, 0);
+                } catch (RemoteException e) {
+                    mController.mEventHandler.post(new Runnable() {
+                        @Override public void run() {
+                            mController.unregisterMediaButtonIntent(mMediaIntent);
+                        }
+                    });
+                }
+            }
+        }
+
+        public void unlinkToRcClientDeath() {
+            if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
+                try {
+                    mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
+                    mRcClientDeathHandler = null;
+                } catch (java.util.NoSuchElementException e) {
+                    // not much we can do here
+                    Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        public void destroy() {
+            unlinkToRcClientDeath();
+            if (mToken != null) {
+                mToken.unlinkToDeath(this, 0);
+                mToken = null;
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            mController.unregisterMediaButtonIntent(mMediaIntent);
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            destroy(); // unlink exception handled inside method
+            super.finalize();
+        }
+    }
+
+    /**
+     *  The stack of remote control event receivers.
+     *  Code sections and methods that modify the remote control event receiver stack are
+     *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
+     *  stack, audio focus or RC, can lead to a change in the remote control display
+     */
+    private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
+
+    /**
+     * The component the telephony package can register so telephony calls have priority to
+     * handle media button events
+     */
+    private ComponentName mMediaReceiverForCalls = null;
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the remote control focus stack
+     */
+    private void dumpRCStack(PrintWriter pw) {
+        pw.println("\nRemote Control stack entries (last is top of stack):");
+        synchronized(mRCStack) {
+            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while(stackIterator.hasNext()) {
+                RemoteControlStackEntry rcse = stackIterator.next();
+                pw.println("  pi: " + rcse.mMediaIntent +
+                        " -- pack: " + rcse.mCallingPackageName +
+                        "  -- ercvr: " + rcse.mReceiverComponent +
+                        "  -- client: " + rcse.mRcClient +
+                        "  -- uid: " + rcse.mCallingUid +
+                        "  -- type: " + rcse.mPlaybackType +
+                        "  state: " + rcse.mPlaybackState);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the remote control stack, focusing
+     * on RemoteControlClient data
+     */
+    private void dumpRCCStack(PrintWriter pw) {
+        pw.println("\nRemote Control Client stack entries (last is top of stack):");
+        synchronized(mRCStack) {
+            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while(stackIterator.hasNext()) {
+                RemoteControlStackEntry rcse = stackIterator.next();
+                pw.println("  uid: " + rcse.mCallingUid +
+                        "  -- id: " + rcse.mRccId +
+                        "  -- type: " + rcse.mPlaybackType +
+                        "  -- state: " + rcse.mPlaybackState +
+                        "  -- vol handling: " + rcse.mPlaybackVolumeHandling +
+                        "  -- vol: " + rcse.mPlaybackVolume +
+                        "  -- volMax: " + rcse.mPlaybackVolumeMax +
+                        "  -- volObs: " + rcse.mRemoteVolumeObs);
+            }
+            synchronized(mCurrentRcLock) {
+                pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
+            }
+        }
+        synchronized (mMainRemote) {
+            pw.println("\nRemote Volume State:");
+            pw.println("  has remote: " + mHasRemotePlayback);
+            pw.println("  is remote active: " + mMainRemoteIsActive);
+            pw.println("  rccId: " + mMainRemote.mRccId);
+            pw.println("  volume handling: "
+                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
+                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
+            pw.println("  volume: " + mMainRemote.mVolume);
+            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
+        }
+    }
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the list of remote control displays
+     */
+    private void dumpRCDList(PrintWriter pw) {
+        pw.println("\nRemote Control Display list entries:");
+        synchronized(mRCStack) {
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                pw.println("  IRCD: " + di.mRcDisplay +
+                        "  -- w:" + di.mArtworkExpectedWidth +
+                        "  -- h:" + di.mArtworkExpectedHeight+
+                        "  -- wantsPosSync:" + di.mWantsPositionSync);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Remove any entry in the remote control stack that has the same package name as packageName
+     * Pre-condition: packageName != null
+     */
+    private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) {
+        synchronized(mRCStack) {
+            if (mRCStack.empty()) {
+                return;
+            } else {
+                final PackageManager pm = mContext.getPackageManager();
+                RemoteControlStackEntry oldTop = mRCStack.peek();
+                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                // iterate over the stack entries
+                // (using an iterator on the stack so we can safely remove an entry after having
+                //  evaluated it, traversal order doesn't matter here)
+                while(stackIterator.hasNext()) {
+                    RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
+                    if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
+                        // a stack entry is from the package being removed, remove it from the stack
+                        stackIterator.remove();
+                        rcse.destroy();
+                    } else if (rcse.mReceiverComponent != null) {
+                        try {
+                            // Check to see if this receiver still exists.
+                            pm.getReceiverInfo(rcse.mReceiverComponent, 0);
+                        } catch (PackageManager.NameNotFoundException e) {
+                            // Not found -- remove it!
+                            stackIterator.remove();
+                            rcse.destroy();
+                        }
+                    }
+                }
+                if (mRCStack.empty()) {
+                    // no saved media button receiver
+                    mEventHandler.sendMessage(
+                            mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
+                                    null));
+                } else if (oldTop != mRCStack.peek()) {
+                    // the top of the stack has changed, save it in the system settings
+                    // by posting a message to persist it; only do this however if it has
+                    // a concrete component name (is not a transient registration)
+                    RemoteControlStackEntry rcse = mRCStack.peek();
+                    if (rcse.mReceiverComponent != null) {
+                        mEventHandler.sendMessage(
+                                mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
+                                        rcse.mReceiverComponent));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Restore remote control receiver from the system settings.
+     */
+    protected void restoreMediaButtonReceiver() {
+        String receiverName = Settings.System.getStringForUser(mContentResolver,
+                Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
+        if ((null != receiverName) && !receiverName.isEmpty()) {
+            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
+            if (eventReceiver == null) {
+                // an invalid name was persisted
+                return;
+            }
+            // construct a PendingIntent targeted to the restored component name
+            // for the media button and register it
+            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+            //     the associated intent will be handled by the component being registered
+            mediaButtonIntent.setComponent(eventReceiver);
+            PendingIntent pi = PendingIntent.getBroadcast(mContext,
+                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
+            registerMediaButtonIntent(pi, eventReceiver, null);
+        }
+    }
+
+    /**
+     * Helper function:
+     * Set the new remote control receiver at the top of the RC focus stack.
+     * Called synchronized on mAudioFocusLock, then mRCStack
+     * precondition: mediaIntent != null
+     */
+    private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target,
+            IBinder token) {
+        // already at top of stack?
+        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
+            return;
+        }
+        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
+                mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+        RemoteControlStackEntry rcse = null;
+        boolean wasInsideStack = false;
+        try {
+            for (int index = mRCStack.size()-1; index >= 0; index--) {
+                rcse = mRCStack.elementAt(index);
+                if(rcse.mMediaIntent.equals(mediaIntent)) {
+                    // ok to remove element while traversing the stack since we're leaving the loop
+                    mRCStack.removeElementAt(index);
+                    wasInsideStack = true;
+                    break;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // not expected to happen, indicates improper concurrent modification
+            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+        }
+        if (!wasInsideStack) {
+            rcse = new RemoteControlStackEntry(this, mediaIntent, target, token);
+        }
+        mRCStack.push(rcse); // rcse is never null
+
+        // post message to persist the default media button receiver
+        if (target != null) {
+            mEventHandler.sendMessage( mEventHandler.obtainMessage(
+                    MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
+        }
+    }
+
+    /**
+     * Helper function:
+     * Remove the remote control receiver from the RC focus stack.
+     * Called synchronized on mAudioFocusLock, then mRCStack
+     * precondition: pi != null
+     */
+    private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) {
+        try {
+            for (int index = mRCStack.size()-1; index >= 0; index--) {
+                final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                if (rcse.mMediaIntent.equals(pi)) {
+                    rcse.destroy();
+                    // ok to remove element while traversing the stack since we're leaving the loop
+                    mRCStack.removeElementAt(index);
+                    break;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // not expected to happen, indicates improper concurrent modification
+            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mRCStack
+     */
+    private boolean isCurrentRcController(PendingIntent pi) {
+        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
+            return true;
+        }
+        return false;
+    }
+
+    private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
+        Settings.System.putStringForUser(mContentResolver,
+                                         Settings.System.MEDIA_BUTTON_RECEIVER,
+                                         receiver == null ? "" : receiver.flattenToString(),
+                                         UserHandle.USER_CURRENT);
+    }
+
+    //==========================================================================================
+    // Remote control display / client
+    //==========================================================================================
+    /**
+     * Update the remote control displays with the new "focused" client generation
+     */
+    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
+            PendingIntent newMediaIntent, boolean clearing) {
+        synchronized(mRCStack) {
+            if (mRcDisplays.size() > 0) {
+                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+                while (displayIterator.hasNext()) {
+                    final DisplayInfoForServer di = displayIterator.next();
+                    try {
+                        di.mRcDisplay.setCurrentClientId(
+                                newClientGeneration, newMediaIntent, clearing);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
+                        di.release();
+                        displayIterator.remove();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Update the remote control clients with the new "focused" client generation
+     */
+    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
+        // (using an iterator on the stack so we can safely remove an entry if needed,
+        //  traversal order doesn't matter here as we update all entries)
+        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+        while(stackIterator.hasNext()) {
+            RemoteControlStackEntry se = stackIterator.next();
+            if ((se != null) && (se.mRcClient != null)) {
+                try {
+                    se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
+                    stackIterator.remove();
+                    se.unlinkToRcClientDeath();
+                }
+            }
+        }
+    }
+
+    /**
+     * Update the displays and clients with the new "focused" client generation and name
+     * @param newClientGeneration the new generation value matching a client update
+     * @param newMediaIntent the media button event receiver associated with the client.
+     *    May be null, which implies there is no registered media button event receiver.
+     * @param clearing true if the new client generation value maps to a remote control update
+     *    where the display should be cleared.
+     */
+    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
+            PendingIntent newMediaIntent, boolean clearing) {
+        // send the new valid client generation ID to all displays
+        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
+        // send the new valid client generation ID to all clients
+        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_CLEAR event
+     */
+    private void onRcDisplayClear() {
+        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
+
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                mCurrentRcClientGen++;
+                // synchronously update the displays and clients with the new client generation
+                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
+                        null /*newMediaIntent*/, true /*clearing*/);
+            }
+        }
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_UPDATE event
+     */
+    private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
+                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
+
+                    mCurrentRcClientGen++;
+                    // synchronously update the displays and clients with
+                    //      the new client generation
+                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
+                            rcse.mMediaIntent /*newMediaIntent*/,
+                            false /*clearing*/);
+
+                    // tell the current client that it needs to send info
+                    try {
+                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Current valid remote client is dead: "+e);
+                        mCurrentRcClient = null;
+                    }
+                } else {
+                    // the remote control display owner has changed between the
+                    // the message to update the display was sent, and the time it
+                    // gets to be processed (now)
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Helper function:
+     * Called synchronized on mRCStack
+     */
+    private void clearRemoteControlDisplay_syncAfRcs() {
+        synchronized(mCurrentRcLock) {
+            mCurrentRcClient = null;
+        }
+        // will cause onRcDisplayClear() to be called in AudioService's handler thread
+        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
+    }
+
+    /**
+     * Helper function for code readability: only to be called from
+     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
+     *    this method.
+     * Preconditions:
+     *    - called synchronized mAudioFocusLock then on mRCStack
+     *    - mRCStack.isEmpty() is false
+     */
+    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
+        RemoteControlStackEntry rcse = mRCStack.peek();
+        int infoFlagsAboutToBeUsed = infoChangedFlags;
+        // this is where we enforce opt-in for information display on the remote controls
+        //   with the new AudioManager.registerRemoteControlClient() API
+        if (rcse.mRcClient == null) {
+            //Log.w(TAG, "Can't update remote control display with null remote control client");
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+        synchronized(mCurrentRcLock) {
+            if (!rcse.mRcClient.equals(mCurrentRcClient)) {
+                // new RC client, assume every type of information shall be queried
+                infoFlagsAboutToBeUsed = RC_INFO_ALL;
+            }
+            mCurrentRcClient = rcse.mRcClient;
+        }
+        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
+        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
+                infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) );
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mAudioFocusLock, then mRCStack
+     * Check whether the remote control display should be updated, triggers the update if required
+     * @param infoChangedFlags the flags corresponding to the remote control client information
+     *     that has changed, if applicable (checking for the update conditions might trigger a
+     *     clear, rather than an update event).
+     */
+    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
+        // determine whether the remote control display should be refreshed
+        // if either stack is empty, there is a mismatch, so clear the RC display
+        if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+
+        // determine which entry in the AudioFocus stack to consider, and compare against the
+        // top of the stack for the media button event receivers : simply using the top of the
+        // stack would make the entry disappear from the RemoteControlDisplay in conditions such as
+        // notifications playing during music playback.
+        // Crawl the AudioFocus stack from the top until an entry is found with the following
+        // characteristics:
+        // - focus gain on STREAM_MUSIC stream
+        // - non-transient focus gain on a stream other than music
+        FocusStackEntry af = null;
+        try {
+            for (int index = mFocusStack.size()-1; index >= 0; index--) {
+                FocusStackEntry fse = mFocusStack.elementAt(index);
+                if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
+                        || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) {
+                    af = fse;
+                    break;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
+            af = null;
+        }
+        if (af == null) {
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+
+        // if the audio focus and RC owners belong to different packages, there is a mismatch, clear
+        if ((mRCStack.peek().mCallingPackageName != null)
+                && (af.mPackageName != null)
+                && !(mRCStack.peek().mCallingPackageName.compareTo(
+                        af.mPackageName) == 0)) {
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+        // if the audio focus didn't originate from the same Uid as the one in which the remote
+        //   control information will be retrieved, clear
+        if (mRCStack.peek().mCallingUid != af.mCallingUid) {
+            clearRemoteControlDisplay_syncAfRcs();
+            return;
+        }
+
+        // refresh conditions were verified: update the remote controls
+        // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
+        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
+    }
+
+    /**
+     * Helper function:
+     * Post a message to asynchronously move the media button event receiver associated with the
+     * given remote control client ID to the top of the remote control stack
+     * @param rccId
+     */
+    private void postPromoteRcc(int rccId) {
+        sendMsg(mEventHandler, MSG_PROMOTE_RCC, SENDMSG_REPLACE,
+                rccId /*arg1*/, 0, null, 0/*delay*/);
+    }
+
+    private void onPromoteRcc(int rccId) {
+        if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); }
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                // ignore if given RCC ID is already at top of remote control stack
+                if (!mRCStack.isEmpty() && (mRCStack.peek().mRccId == rccId)) {
+                    return;
+                }
+                int indexToPromote = -1;
+                try {
+                    for (int index = mRCStack.size()-1; index >= 0; index--) {
+                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                        if (rcse.mRccId == rccId) {
+                            indexToPromote = index;
+                            break;
+                        }
+                    }
+                    if (indexToPromote >= 0) {
+                        if (DEBUG_RC) { Log.d(TAG, "  moving RCC from index " + indexToPromote
+                                + " to " + (mRCStack.size()-1)); }
+                        final RemoteControlStackEntry rcse = mRCStack.remove(indexToPromote);
+                        mRCStack.push(rcse);
+                        // the RC stack changed, reevaluate the display
+                        checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                    }
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    // not expected to happen, indicates improper concurrent modification
+                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+                }
+            }//synchronized(mRCStack)
+        }//synchronized(mAudioFocusLock)
+    }
+
+    /**
+     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
+     * precondition: mediaIntent != null
+     */
+    protected void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
+            IBinder token) {
+        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
+
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token);
+                // new RC client, assume every type of information shall be queried
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+            }
+        }
+    }
+
+    /**
+     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
+     * precondition: mediaIntent != null, eventReceiver != null
+     */
+    protected void unregisterMediaButtonIntent(PendingIntent mediaIntent)
+    {
+        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
+
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
+                removeMediaButtonReceiver_syncAfRcs(mediaIntent);
+                if (topOfStackWillChange) {
+                    // current RC client will change, assume every type of info needs to be queried
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                }
+            }
+        }
+    }
+
+    /**
+     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
+     * precondition: c != null
+     */
+    protected void registerMediaButtonEventReceiverForCalls(ComponentName c) {
+        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+                != PackageManager.PERMISSION_GRANTED) {
+            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
+            return;
+        }
+        synchronized(mRCStack) {
+            mMediaReceiverForCalls = c;
+        }
+    }
+
+    /**
+     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
+     */
+    protected void unregisterMediaButtonEventReceiverForCalls() {
+        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+                != PackageManager.PERMISSION_GRANTED) {
+            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
+            return;
+        }
+        synchronized(mRCStack) {
+            mMediaReceiverForCalls = null;
+        }
+    }
+
+    /**
+     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
+     * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient
+     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
+     *     without modifying the RC stack, but while still causing the display to refresh (will
+     *     become blank as a result of this)
+     */
+    protected int registerRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient, String callingPackageName) {
+        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
+        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                // store the new display information
+                try {
+                    for (int index = mRCStack.size()-1; index >= 0; index--) {
+                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                        if(rcse.mMediaIntent.equals(mediaIntent)) {
+                            // already had a remote control client?
+                            if (rcse.mRcClientDeathHandler != null) {
+                                // stop monitoring the old client's death
+                                rcse.unlinkToRcClientDeath();
+                            }
+                            // save the new remote control client
+                            rcse.mRcClient = rcClient;
+                            rcse.mCallingPackageName = callingPackageName;
+                            rcse.mCallingUid = Binder.getCallingUid();
+                            if (rcClient == null) {
+                                // here rcse.mRcClientDeathHandler is null;
+                                rcse.resetPlaybackInfo();
+                                break;
+                            }
+                            rccId = rcse.mRccId;
+
+                            // there is a new (non-null) client:
+                            // 1/ give the new client the displays (if any)
+                            if (mRcDisplays.size() > 0) {
+                                plugRemoteControlDisplaysIntoClient_syncRcStack(rcse.mRcClient);
+                            }
+                            // 2/ monitor the new client's death
+                            IBinder b = rcse.mRcClient.asBinder();
+                            RcClientDeathHandler rcdh =
+                                    new RcClientDeathHandler(b, rcse.mMediaIntent);
+                            try {
+                                b.linkToDeath(rcdh, 0);
+                            } catch (RemoteException e) {
+                                // remote control client is DOA, disqualify it
+                                Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
+                                rcse.mRcClient = null;
+                            }
+                            rcse.mRcClientDeathHandler = rcdh;
+                            break;
+                        }
+                    }//for
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    // not expected to happen, indicates improper concurrent modification
+                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+                }
+
+                // if the eventReceiver is at the top of the stack
+                // then check for potential refresh of the remote controls
+                if (isCurrentRcController(mediaIntent)) {
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                }
+            }//synchronized(mRCStack)
+        }//synchronized(mAudioFocusLock)
+        return rccId;
+    }
+
+    /**
+     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
+     * rcClient is guaranteed non-null
+     */
+    protected void unregisterRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient) {
+        if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                boolean topRccChange = false;
+                try {
+                    for (int index = mRCStack.size()-1; index >= 0; index--) {
+                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                        if ((rcse.mMediaIntent.equals(mediaIntent))
+                                && rcClient.equals(rcse.mRcClient)) {
+                            // we found the IRemoteControlClient to unregister
+                            // stop monitoring its death
+                            rcse.unlinkToRcClientDeath();
+                            // reset the client-related fields
+                            rcse.mRcClient = null;
+                            rcse.mCallingPackageName = null;
+                            topRccChange = (index == mRCStack.size()-1);
+                            // there can only be one matching RCC in the RC stack, we're done
+                            break;
+                        }
+                    }
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    // not expected to happen, indicates improper concurrent modification
+                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+                }
+                if (topRccChange) {
+                    // no more RCC for the RCD, check for potential refresh of the remote controls
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * A class to encapsulate all the information about a remote control display.
+     * After instanciation, init() must always be called before the object is added in the list
+     * of displays.
+     * Before being removed from the list of displays, release() must always be called (otherwise
+     * it will leak death handlers).
+     */
+    private class DisplayInfoForServer implements IBinder.DeathRecipient {
+        /** may never be null */
+        private IRemoteControlDisplay mRcDisplay;
+        private IBinder mRcDisplayBinder;
+        private int mArtworkExpectedWidth = -1;
+        private int mArtworkExpectedHeight = -1;
+        private boolean mWantsPositionSync = false;
+
+        public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
+            if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
+            mRcDisplay = rcd;
+            mRcDisplayBinder = rcd.asBinder();
+            mArtworkExpectedWidth = w;
+            mArtworkExpectedHeight = h;
+        }
+
+        public boolean init() {
+            try {
+                mRcDisplayBinder.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                // remote control display is DOA, disqualify it
+                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
+                return false;
+            }
+            return true;
+        }
+
+        public void release() {
+            try {
+                mRcDisplayBinder.unlinkToDeath(this, 0);
+            } catch (java.util.NoSuchElementException e) {
+                // not much we can do here, the display should have been unregistered anyway
+                Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
+            }
+        }
+
+        public void binderDied() {
+            synchronized(mRCStack) {
+                Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
+                // remove the display from the list
+                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+                while (displayIterator.hasNext()) {
+                    final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                    if (di.mRcDisplay == mRcDisplay) {
+                        if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
+                        displayIterator.remove();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * The remote control displays.
+     * Access synchronized on mRCStack
+     */
+    private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
+
+    /**
+     * Plug each registered display into the specified client
+     * @param rcc, guaranteed non null
+     */
+    private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
+        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+        while (displayIterator.hasNext()) {
+            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+            try {
+                rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
+                        di.mArtworkExpectedHeight);
+                if (di.mWantsPositionSync) {
+                    rcc.setWantsSyncForDisplay(di.mRcDisplay, true);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
+            }
+        }
+    }
+
+    /**
+     * Is the remote control display interface already registered
+     * @param rcd
+     * @return true if the IRemoteControlDisplay is already in the list of displays
+     */
+    private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
+        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+        while (displayIterator.hasNext()) {
+            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+            if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Register an IRemoteControlDisplay.
+     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
+     * at the top of the stack to update the new display with its information.
+     * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
+     * @param rcd the IRemoteControlDisplay to register. No effect if null.
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     */
+    protected void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
+        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
+                    return;
+                }
+                DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
+                if (!di.init()) {
+                    if (DEBUG_RC) Log.e(TAG, " error registering RCD");
+                    return;
+                }
+                // add RCD to list of displays
+                mRcDisplays.add(di);
+
+                // let all the remote control clients know there is a new display (so the remote
+                //   control stack traversal order doesn't matter).
+                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mRcClient != null) {
+                        try {
+                            rcse.mRcClient.plugRemoteControlDisplay(rcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error connecting RCD to client: ", e);
+                        }
+                    }
+                }
+
+                // we have a new display, of which all the clients are now aware: have it be updated
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
+            }
+        }
+    }
+
+    /**
+     * Unregister an IRemoteControlDisplay.
+     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
+     * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
+     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
+     */
+    protected void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
+        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
+        synchronized(mRCStack) {
+            if (rcd == null) {
+                return;
+            }
+
+            boolean displayWasPluggedIn = false;
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext() && !displayWasPluggedIn) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    displayWasPluggedIn = true;
+                    di.release();
+                    displayIterator.remove();
+                }
+            }
+
+            if (displayWasPluggedIn) {
+                // disconnect this remote control display from all the clients, so the remote
+                //   control stack traversal order doesn't matter
+                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    final RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mRcClient != null) {
+                        try {
+                            rcse.mRcClient.unplugRemoteControlDisplay(rcd);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error disconnecting remote control display to client: ", e);
+                        }
+                    }
+                }
+            } else {
+                if (DEBUG_RC) Log.w(TAG, "  trying to unregister unregistered RCD");
+            }
+        }
+    }
+
+    /**
+     * Update the size of the artwork used by an IRemoteControlDisplay.
+     * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
+     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     */
+    protected void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
+        synchronized(mRCStack) {
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            boolean artworkSizeUpdate = false;
+            while (displayIterator.hasNext() && !artworkSizeUpdate) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
+                        di.mArtworkExpectedWidth = w;
+                        di.mArtworkExpectedHeight = h;
+                        artworkSizeUpdate = true;
+                    }
+                }
+            }
+            if (artworkSizeUpdate) {
+                // RCD is currently plugged in and its artwork size has changed, notify all RCCs,
+                // stack traversal order doesn't matter
+                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    final RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mRcClient != null) {
+                        try {
+                            rcse.mRcClient.setBitmapSizeForDisplay(rcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
+     * playback position to verify that the estimated position has not drifted from the actual
+     * position. By default the check is not performed.
+     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
+     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
+     *     or disabled. Not null.
+     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
+     *     to the framework will regularly compare the estimated playback position with the actual
+     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
+     *     detected.
+     */
+    protected void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
+            boolean wantsSync) {
+        synchronized(mRCStack) {
+            boolean rcdRegistered = false;
+            // store the information about this display
+            // (display stack traversal order doesn't matter).
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    di.mWantsPositionSync = wantsSync;
+                    rcdRegistered = true;
+                    break;
+                }
+            }
+            if (!rcdRegistered) {
+                return;
+            }
+            // notify all current RemoteControlClients
+            // (stack traversal order doesn't matter as we notify all RCCs)
+            final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while (stackIterator.hasNext()) {
+                final RemoteControlStackEntry rcse = stackIterator.next();
+                if (rcse.mRcClient != null) {
+                    try {
+                        rcse.mRcClient.setWantsSyncForDisplay(rcd, wantsSync);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e);
+                    }
+                }
+            }
+        }
+    }
+
+    protected void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
+        // ignore position change requests if invalid generation ID
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if (mCurrentRcClientGen != generationId) {
+                    return;
+                }
+            }
+        }
+        // discard any unprocessed seek request in the message queue, and replace with latest
+        sendMsg(mEventHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */,
+                0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */);
+    }
+
+    private void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
+        if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId +
+                ", timeMs=" + timeMs + ")");
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) {
+                    // tell the current client to seek to the requested location
+                    try {
+                        mCurrentRcClient.seekTo(generationId, timeMs);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Current valid remote client is dead: "+e);
+                        mCurrentRcClient = null;
+                    }
+                }
+            }
+        }
+    }
+
+    protected void setPlaybackInfoForRcc(int rccId, int what, int value) {
+        sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
+                rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);
+    }
+
+    // handler for MSG_RCC_NEW_PLAYBACK_INFO
+    private void onNewPlaybackInfoForRcc(int rccId, int key, int value) {
+        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId +
+                ", what=" + key + ",val=" + value + ")");
+        synchronized(mRCStack) {
+            // iterating from top of stack as playback information changes are more likely
+            //   on entries at the top of the remote control stack
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if (rcse.mRccId == rccId) {
+                        switch (key) {
+                            case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE:
+                                rcse.mPlaybackType = value;
+                                postReevaluateRemote();
+                                break;
+                            case RemoteControlClient.PLAYBACKINFO_VOLUME:
+                                rcse.mPlaybackVolume = value;
+                                synchronized (mMainRemote) {
+                                    if (rccId == mMainRemote.mRccId) {
+                                        mMainRemote.mVolume = value;
+                                        mVolumeController.postHasNewRemotePlaybackInfo();
+                                    }
+                                }
+                                break;
+                            case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX:
+                                rcse.mPlaybackVolumeMax = value;
+                                synchronized (mMainRemote) {
+                                    if (rccId == mMainRemote.mRccId) {
+                                        mMainRemote.mVolumeMax = value;
+                                        mVolumeController.postHasNewRemotePlaybackInfo();
+                                    }
+                                }
+                                break;
+                            case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING:
+                                rcse.mPlaybackVolumeHandling = value;
+                                synchronized (mMainRemote) {
+                                    if (rccId == mMainRemote.mRccId) {
+                                        mMainRemote.mVolumeHandling = value;
+                                        mVolumeController.postHasNewRemotePlaybackInfo();
+                                    }
+                                }
+                                break;
+                            case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
+                                rcse.mPlaybackStream = value;
+                                break;
+                            default:
+                                Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
+                                break;
+                        }
+                        return;
+                    }
+                }//for
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index mRCStack on onNewPlaybackInfoForRcc, lock error? ", e);
+            }
+        }
+    }
+
+    protected void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
+        sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE,
+                rccId /* arg1 */, state /* arg2 */,
+                new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */);
+    }
+
+    protected void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) {
+        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
+                + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
+        synchronized(mRCStack) {
+            // iterating from top of stack as playback information changes are more likely
+            //   on entries at the top of the remote control stack
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if (rcse.mRccId == rccId) {
+                        rcse.mPlaybackState = newState;
+                        synchronized (mMainRemote) {
+                            if (rccId == mMainRemote.mRccId) {
+                                mMainRemoteIsActive = isPlaystateActive(state);
+                                postReevaluateRemote();
+                            }
+                        }
+                        // an RCC moving to a "playing" state should become the media button
+                        //   event receiver so it can be controlled, without requiring the
+                        //   app to re-register its receiver
+                        if (isPlaystateActive(state)) {
+                            postPromoteRcc(rccId);
+                        }
+                    }
+                }//for
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index on mRCStack in onNewPlaybackStateForRcc, lock error? ", e);
+            }
+        }
+    }
+
+    protected void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
+        sendMsg(mEventHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE,
+                rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */);
+    }
+
+    // handler for MSG_RCC_NEW_VOLUME_OBS
+    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
+        synchronized(mRCStack) {
+            // The stack traversal order doesn't matter because there is only one stack entry
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if (rcse.mRccId == rccId) {
+                        rcse.mRemoteVolumeObs = rvo;
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+            }
+        }
+    }
+
+    /**
+     * Checks if a remote client is active on the supplied stream type. Update the remote stream
+     * volume state if found and playing
+     * @param streamType
+     * @return false if no remote playing is currently playing
+     */
+    protected boolean checkUpdateRemoteStateIfActive(int streamType) {
+        synchronized(mRCStack) {
+            // iterating from top of stack as active playback is more likely on entries at the top
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
+                            && isPlaystateActive(rcse.mPlaybackState.mState)
+                            && (rcse.mPlaybackStream == streamType)) {
+                        if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
+                                + ", vol =" + rcse.mPlaybackVolume);
+                        synchronized (mMainRemote) {
+                            mMainRemote.mRccId = rcse.mRccId;
+                            mMainRemote.mVolume = rcse.mPlaybackVolume;
+                            mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax;
+                            mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling;
+                            mMainRemoteIsActive = true;
+                        }
+                        return true;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+            }
+        }
+        synchronized (mMainRemote) {
+            mMainRemoteIsActive = false;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the given playback state is considered "active", i.e. it describes a state
+     * where playback is happening, or about to
+     * @param playState the playback state to evaluate
+     * @return true if active, false otherwise (inactive or unknown)
+     */
+    private static boolean isPlaystateActive(int playState) {
+        switch (playState) {
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+            case RemoteControlClient.PLAYSTATE_REWINDING:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    protected void adjustRemoteVolume(int streamType, int direction, int flags) {
+        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        boolean volFixed = false;
+        synchronized (mMainRemote) {
+            if (!mMainRemoteIsActive) {
+                if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client");
+                return;
+            }
+            rccId = mMainRemote.mRccId;
+            volFixed = (mMainRemote.mVolumeHandling ==
+                    RemoteControlClient.PLAYBACK_VOLUME_FIXED);
+        }
+        // unlike "local" stream volumes, we can't compute the new volume based on the direction,
+        // we can only notify the remote that volume needs to be updated, and we'll get an async'
+        // update through setPlaybackInfoForRcc()
+        if (!volFixed) {
+            sendVolumeUpdateToRemote(rccId, direction);
+        }
+
+        // fire up the UI
+        mVolumeController.postRemoteVolumeChanged(streamType, flags);
+    }
+
+    private void sendVolumeUpdateToRemote(int rccId, int direction) {
+        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
+        if (direction == 0) {
+            // only handling discrete events
+            return;
+        }
+        IRemoteVolumeObserver rvo = null;
+        synchronized (mRCStack) {
+            // The stack traversal order doesn't matter because there is only one stack entry
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
+                    if (rcse.mRccId == rccId) {
+                        rvo = rcse.mRemoteVolumeObs;
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+            }
+        }
+        if (rvo != null) {
+            try {
+                rvo.dispatchRemoteVolumeUpdate(direction, -1);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error dispatching relative volume update", e);
+            }
+        }
+    }
+
+    protected int getRemoteStreamMaxVolume() {
+        synchronized (mMainRemote) {
+            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
+                return 0;
+            }
+            return mMainRemote.mVolumeMax;
+        }
+    }
+
+    protected int getRemoteStreamVolume() {
+        synchronized (mMainRemote) {
+            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
+                return 0;
+            }
+            return mMainRemote.mVolume;
+        }
+    }
+
+    protected void setRemoteStreamVolume(int vol) {
+        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
+        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        synchronized (mMainRemote) {
+            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
+                return;
+            }
+            rccId = mMainRemote.mRccId;
+        }
+        IRemoteVolumeObserver rvo = null;
+        synchronized (mRCStack) {
+            // The stack traversal order doesn't matter because there is only one stack entry
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
+                    if (rcse.mRccId == rccId) {
+                        rvo = rcse.mRemoteVolumeObs;
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+            }
+        }
+        if (rvo != null) {
+            try {
+                rvo.dispatchRemoteVolumeUpdate(0, vol);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error dispatching absolute volume update", e);
+            }
+        }
+    }
+
+    /**
+     * Call to make AudioService reevaluate whether it's in a mode where remote players should
+     * have their volume controlled. In this implementation this is only to reset whether
+     * VolumePanel should display remote volumes
+     */
+    private void postReevaluateRemote() {
+        sendMsg(mEventHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
+    }
+
+    private void onReevaluateRemote() {
+        if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); }
+        // is there a registered RemoteControlClient that is handling remote playback
+        boolean hasRemotePlayback = false;
+        synchronized (mRCStack) {
+            // iteration stops when PLAYBACK_TYPE_REMOTE is found, so remote control stack
+            //   traversal order doesn't matter
+            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while(stackIterator.hasNext()) {
+                RemoteControlStackEntry rcse = stackIterator.next();
+                if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
+                    hasRemotePlayback = true;
+                    break;
+                }
+            }
+        }
+        synchronized (mMainRemote) {
+            if (mHasRemotePlayback != hasRemotePlayback) {
+                mHasRemotePlayback = hasRemotePlayback;
+                mVolumeController.postRemoteSliderVisibility(hasRemotePlayback);
+            }
+        }
+    }
+
+}
diff --git a/media/java/android/media/VolumeController.java b/media/java/android/media/VolumeController.java
new file mode 100644
index 0000000..2d12bf2
--- /dev/null
+++ b/media/java/android/media/VolumeController.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * @hide
+ */
+public interface VolumeController {
+
+    public void postHasNewRemotePlaybackInfo();
+
+    public void postRemoteVolumeChanged(int streamType, int flags);
+
+    public void postRemoteSliderVisibility(boolean visible);
+}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 5856057..d876bd2 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -542,7 +542,7 @@
     nativeFormat = Image_getPixelFormat(env, format);
 
     sp<BufferQueue> bq = new BufferQueue();
-    sp<CpuConsumer> consumer = new CpuConsumer(bq, maxImages);
+    sp<CpuConsumer> consumer = new CpuConsumer(bq, true, maxImages);
     // TODO: throw dvm exOutOfMemoryError?
     if (consumer == NULL) {
         jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 1f478d2..5e4fabd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -271,10 +271,10 @@
         // (streaming)
 
         int requestId1;
-        requestId1 = mCameraUser.submitRequest(request, /* streaming */true);
+        requestId1 = mCameraUser.submitRequest(request, /* streaming */false);
         assertTrue("Request IDs should be non-negative", requestId1 >= 0);
 
-        int requestIdStreaming = mCameraUser.submitRequest(request, /* streaming */false);
+        int requestIdStreaming = mCameraUser.submitRequest(request, /* streaming */true);
         assertTrue("Request IDs should be non-negative", requestIdStreaming >= 0);
         assertNotSame("Request IDs should be unique for multiple requests", requestId1,
                 requestIdStreaming);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 0c2f3a3..131441b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -19,8 +19,10 @@
 import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.graphics.ImageFormat;
+import android.graphics.Rect;
 import android.hardware.photography.CameraMetadata;
 import android.hardware.photography.Rational;
+import android.hardware.photography.Size;
 
 import static android.hardware.photography.CameraMetadata.*;
 
@@ -223,6 +225,10 @@
 
         assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE));
 
+        // Write/read null values
+        mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, null);
+        assertEquals(null, mMetadata.readValues(ANDROID_COLOR_CORRECTION_MODE));
+
         // Write 0 values
         mMetadata.writeValues(ANDROID_COLOR_CORRECTION_MODE, new byte[] {});
 
@@ -286,13 +292,21 @@
     }
 
     private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T value) {
+        assertFalse("Use checkKeyGetAndSetArray to compare array Keys", type.isArray());
+
         Key<T> key = new Key<T>(keyStr, type);
         assertNull(mMetadata.get(key));
+        mMetadata.set(key, null);
+        assertNull(mMetadata.get(key));
         mMetadata.set(key, value);
-        assertEquals(value, mMetadata.get(key));
+
+        T actual = mMetadata.get(key);
+        assertEquals(value, actual);
     }
 
     private <T> void checkKeyGetAndSetArray(String keyStr, Class<T> type, T value) {
+        assertTrue(type.isArray());
+
         Key<T> key = new Key<T>(keyStr, type);
         assertNull(mMetadata.get(key));
         mMetadata.set(key, value);
@@ -508,4 +522,73 @@
             assertEquals(expectedIntValues[i], bf.getInt());
         }
     }
+
+    @SmallTest
+    public void testReadWriteSize() {
+        // int32 x n
+        checkKeyGetAndSet("android.jpeg.thumbnailSize", Size.class, new Size(123, 456));
+
+        // int32 x 2 x n
+        checkKeyGetAndSetArray("android.scaler.availableJpegSizes", Size[].class, new Size[] {
+            new Size(123, 456),
+            new Size(0xDEAD, 0xF00D),
+            new Size(0xF00, 0xB00)
+        });
+    }
+
+    @SmallTest
+    public void testReadWriteRectangle() {
+        // int32 x n
+        checkKeyGetAndSet("android.scaler.cropRegion", Rect.class, new Rect(10, 11, 1280, 1024));
+
+        // int32 x 2 x n
+        checkKeyGetAndSetArray("android.statistics.faceRectangles", Rect[].class, new Rect[] {
+            new Rect(110, 111, 11280, 11024),
+            new Rect(210, 111, 21280, 21024),
+            new Rect(310, 111, 31280, 31024)
+        });
+    }
+
+    @SmallTest
+    public void testReadWriteString() {
+        // (byte) string
+        Key<String> gpsProcessingMethodKey =
+                new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
+
+        String helloWorld = new String("HelloWorld");
+        byte[] helloWorldBytes = new byte[] {
+                'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0' };
+
+        mMetadata.set(gpsProcessingMethodKey, helloWorld);
+
+        String actual = mMetadata.get(gpsProcessingMethodKey);
+        assertEquals(helloWorld, actual);
+
+        byte[] actualBytes = mMetadata.readValues(getTag(gpsProcessingMethodKey.getName()));
+        assertArrayEquals(helloWorldBytes, actualBytes);
+
+        // Does not yet test as a string[] since we don't support that in native code.
+
+        // (byte) string
+        Key<String[]> gpsProcessingMethodKeyArray =
+                new Key<String[]>("android.jpeg.gpsProcessingMethod", String[].class);
+
+        String[] gpsStrings = new String[] { "HelloWorld", "FooBar", "Shazbot" };
+        byte[] gpsBytes = new byte[] {
+                'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '\0',
+                'F', 'o', 'o', 'B', 'a', 'r', '\0',
+                'S', 'h', 'a', 'z', 'b', 'o', 't', '\0'};
+
+        mMetadata.set(gpsProcessingMethodKeyArray, gpsStrings);
+
+        String[] actualArray = mMetadata.get(gpsProcessingMethodKeyArray);
+        assertArrayEquals(gpsStrings, actualArray);
+
+        byte[] actualBytes2 = mMetadata.readValues(getTag(gpsProcessingMethodKeyArray.getName()));
+        assertArrayEquals(gpsBytes, actualBytes2);
+    }
+
+    <T> void compareGeneric(T expected, T actual) {
+        assertEquals(expected, actual);
+    }
 }
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 7d77c48..7039d6d 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -35,6 +35,7 @@
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
 
diff --git a/packages/Keyguard/res/values-hdpi/dimens.xml b/packages/Keyguard/res/values-hdpi/dimens.xml
new file mode 100644
index 0000000..2c209e2
--- /dev/null
+++ b/packages/Keyguard/res/values-hdpi/dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+
+    <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_height">345dp</dimen>
+
+</resources>
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
index a68fcdf..8ae0302 100644
--- a/packages/PrintSpooler/Android.mk
+++ b/packages/PrintSpooler/Android.mk
@@ -22,7 +22,7 @@
 
 LOCAL_PACKAGE_NAME := PrintSpooler
 
-LOCAL_JAVA_LIBRARIES := framework
+LOCAL_JAVA_LIBRARIES := framework-base
 
 LOCAL_CERTIFICATE := platform
 
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index fbb0060..f0bbfa4 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -46,7 +46,8 @@
 
         <activity
             android:name=".PrintJobConfigActivity"
-            android:exported="true">
+            android:exported="true"
+            android:theme="@android:style/Theme.Holo.Light.Dialog.NoActionBar">
         </activity>
 
     </application>
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity.xml b/packages/PrintSpooler/res/layout/print_job_config_activity.xml
index 51e425d..32bc15a 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity.xml
@@ -5,7 +5,7 @@
      you may not use this 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,
@@ -16,246 +16,262 @@
 
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:scrollbars="vertical">
 
     <GridLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
         android:orientation="vertical"
         android:columnCount="2">
 
-        <EditText
-            android:id="@+id/copies_edittext"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="0"
-            android:layout_column="1"
-            android:minWidth="150dip"
-            android:inputType="number"
-            android:selectAllOnFocus="true">
-        </EditText>
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="0"
-            android:layout_column="0"
-            android:text="@string/label_copies"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:labelFor="@id/copies_edittext">
-        </TextView>
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="1"
-            android:layout_column="0"
-            android:text="@string/label_destination"
-            android:textAppearance="?android:attr/textAppearanceMedium">
-        </TextView>
+        <!-- Destination -->
 
         <Spinner
             android:id="@+id/destination_spinner"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
+            android:layout_gravity="fill_horizontal"
+            android:layout_marginLeft="32dip"
+            android:layout_marginRight="32dip"
+            android:layout_marginBottom="12dip"
+            android:layout_row="0"
+            android:layout_column="0"
+            android:layout_columnSpan="2"
+            android:minHeight="?android:attr/listPreferredItemHeightSmall">
+        </Spinner>
+
+        <!-- Copies -->
+
+        <view
+            class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+            android:id="@+id/copies_edittext"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="32dip"
+            android:layout_marginRight="12dip"
+            android:layout_marginBottom="12dip"
+            android:layout_row="2"
+            android:layout_column="0"
+            android:layout_gravity="bottom"
+            android:inputType="numberDecimal"
+            android:selectAllOnFocus="true"
+            android:minWidth="150dip">
+        </view>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="32dip"
+            android:layout_marginTop="12dip"
             android:layout_marginRight="12dip"
             android:layout_row="1"
-            android:layout_column="1"
-            android:minWidth="150dip">
-        </Spinner>
-
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="2"
             android:layout_column="0"
-            android:text="@string/label_media_size"
-            android:textAppearance="?android:attr/textAppearanceMedium">
+            android:layout_gravity="left|bottom"
+            android:text="@string/label_copies"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textStyle="bold"
+            android:labelFor="@id/copies_edittext">
         </TextView>
 
+        <!-- Paper size -->
+
         <Spinner
-            android:id="@+id/media_size_spinner"
+            android:id="@+id/paper_size_spinner"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
+            android:layout_marginRight="32dip"
+            android:layout_marginBottom="12dip"
             android:layout_row="2"
             android:layout_column="1"
             android:minWidth="150dip">
         </Spinner>
 
-
         <TextView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginLeft="12dip"
+            android:layout_marginRight="32dip"
+            android:layout_marginTop="12dip"
+            android:layout_row="1"
+            android:layout_column="1"
+            android:text="@string/label_paper_size"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textStyle="bold"
+            android:labelFor="@id/paper_size_spinner">
+        </TextView>
+
+        <!-- Color -->
+
+        <Spinner
+            android:id="@+id/color_spinner"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="32dip"
+            android:layout_marginRight="12dip"
+            android:layout_marginBottom="12dip"
+            android:layout_row="4"
+            android:layout_column="0"
+            android:minWidth="150dip">
+        </Spinner>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="32dip"
+            android:layout_marginTop="12dip"
             android:layout_marginRight="12dip"
             android:layout_row="3"
             android:layout_column="0"
-            android:text="@string/label_resolution"
-            android:textAppearance="?android:attr/textAppearanceMedium">
+            android:text="@string/label_color"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textStyle="bold"
+            android:labelFor="@id/color_spinner">
         </TextView>
 
-        <Spinner
-            android:id="@+id/resolution_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="3"
-            android:layout_column="1"
-            android:minWidth="150dip">
-        </Spinner>
-
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="4"
-            android:layout_column="0"
-            android:text="@string/label_input_tray"
-            android:textAppearance="?android:attr/textAppearanceMedium">
-        </TextView>
-
-        <Spinner
-            android:id="@+id/input_tray_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="4"
-            android:layout_column="1"
-            android:minWidth="150dip">
-        </Spinner>
-
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="5"
-            android:layout_column="0"
-            android:text="@string/label_output_tray"
-            android:textAppearance="?android:attr/textAppearanceMedium">
-        </TextView>
-
-        <Spinner
-            android:id="@+id/output_tray_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="5"
-            android:layout_column="1"
-            android:minWidth="150dip">
-        </Spinner>
-
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="6"
-            android:layout_column="0"
-            android:text="@string/label_duplex_mode"
-            android:textAppearance="?android:attr/textAppearanceMedium">
-        </TextView>
-
-        <Spinner
-            android:id="@+id/duplex_mode_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="6"
-            android:layout_column="1"
-            android:minWidth="150dip">
-        </Spinner>
-
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="7"
-            android:layout_column="0"
-            android:text="@string/label_color_mode"
-            android:textAppearance="?android:attr/textAppearanceMedium">
-        </TextView>
-
-        <Spinner
-            android:id="@+id/color_mode_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="7"
-            android:layout_column="1"
-            android:minWidth="150dip">
-        </Spinner>
-
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="8"
-            android:layout_column="0"
-            android:text="@string/label_fitting_mode"
-            android:textAppearance="?android:attr/textAppearanceMedium">
-        </TextView>
-
-        <Spinner
-            android:id="@+id/fitting_mode_spinner"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="8"
-            android:layout_column="1"
-            android:minWidth="150dip">
-        </Spinner>
-
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="9"
-            android:layout_column="0"
-            android:text="@string/label_orientation"
-            android:textAppearance="?android:attr/textAppearanceMedium">
-        </TextView>
+        <!-- Orientation -->
 
         <Spinner
             android:id="@+id/orientation_spinner"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_marginLeft="12dip"
-            android:layout_marginRight="12dip"
-            android:layout_row="9"
+            android:layout_marginRight="32dip"
+            android:layout_marginBottom="12dip"
+            android:layout_row="4"
             android:layout_column="1"
             android:minWidth="150dip">
         </Spinner>
 
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="12dip"
+            android:layout_marginTop="12dip"
+            android:layout_marginRight="32dip"
+            android:layout_row="3"
+            android:layout_column="1"
+            android:text="@string/label_orientation"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textStyle="bold"
+            android:labelFor="@id/orientation_spinner">
+        </TextView>
+
+        <!-- Pages -->
+
+        <Spinner
+            android:id="@+id/range_options_spinner"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="32dip"
+            android:layout_marginRight="12dip"
+            android:layout_row="6"
+            android:layout_column="0"
+            android:minWidth="150dip">
+        </Spinner>
+
+        <view
+            class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+            android:id="@+id/page_range_edittext"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="12dip"
+            android:layout_marginRight="32dip"
+            android:layout_row="6"
+            android:layout_column="1"
+            android:layout_gravity="bottom"
+            android:selectAllOnFocus="true"
+            android:minWidth="150dip"
+            android:hint="@string/pages_range_example"
+            android:inputType="textNoSuggestions"
+            android:visibility="gone">
+        </view>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="32dip"
+            android:layout_marginTop="12dip"
+            android:layout_marginRight="12dip"
+            android:layout_row="5"
+            android:layout_column="0"
+            android:text="@string/label_pages"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textStyle="bold"
+            android:labelFor="@id/range_options_spinner">
+        </TextView>
+
+        <!-- Print pereview  -->
+
+        <ImageView
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="fill_horizontal"
+            android:layout_marginLeft="32dip"
+            android:layout_marginTop="32dip"
+            android:layout_marginRight="32dip"
+            android:layout_row="7"
+            android:layout_column="0"
+            android:layout_columnSpan="2"
+            android:background="?android:attr/listDivider"
+            android:contentDescription="@null">
+        </ImageView>
+
+        <Button
+            android:id="@+id/print_preview_button"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="fill_horizontal"
+            android:layout_marginLeft="32dip"
+            android:layout_marginRight="32dip"
+            android:layout_row="8"
+            android:layout_column="0"
+            android:layout_columnSpan="2"
+            android:text="@string/print_preview"
+            android:gravity="left|center_vertical"
+            android:background="?android:attr/selectableItemBackground">
+        </Button>
+
+        <ImageView
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="fill_horizontal"
+            android:layout_marginLeft="32dip"
+            android:layout_marginRight="32dip"
+            android:layout_marginBottom="32dip"
+            android:layout_row="9"
+            android:layout_column="0"
+            android:layout_columnSpan="2"
+            android:background="?android:attr/listDivider"
+            android:contentDescription="@null">
+        </ImageView>
+
+        <ImageView
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="fill_horizontal"
+            android:layout_row="10"
+            android:layout_column="0"
+            android:layout_columnSpan="2"
+            android:background="?android:attr/listDivider"
+            android:contentDescription="@null">
+        </ImageView>
+
+        <Button
+            android:id="@+id/print_button"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="fill_horizontal"
+            android:layout_row="11"
+            android:layout_column="0"
+            android:layout_columnSpan="2"
+            android:padding="0dip"
+            android:text="@string/print_button"
+            android:background="?android:attr/selectableItemBackground">
+        </Button>
+
     </GridLayout>
 
 </ScrollView>
diff --git a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
new file mode 100644
index 0000000..66c6724
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+
+<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:orientation="vertical"
+    android:gravity="center_vertical">
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textIsSelectable="false">
+    </TextView>
+
+    <TextView
+        android:id="@+id/subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textIsSelectable="false"
+        android:visibility="gone">
+
+    </TextView>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/menu/print_job_config_activity.xml b/packages/PrintSpooler/res/values/constants.xml
similarity index 65%
rename from packages/PrintSpooler/res/menu/print_job_config_activity.xml
rename to packages/PrintSpooler/res/values/constants.xml
index 149c274..96cdeb1 100644
--- a/packages/PrintSpooler/res/menu/print_job_config_activity.xml
+++ b/packages/PrintSpooler/res/values/constants.xml
@@ -13,9 +13,15 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/print_button"
-          android:title="@string/print_button"
-          android:showAsAction="ifRoom">
-    </item>
-</menu>
+
+<resources>
+
+    <integer name="page_option_value_all">0</integer>
+    <integer name="page_option_value_page_range">1</integer>
+
+    <integer-array name="page_options_values" translatable="false">
+        <item>@integer/page_option_value_all</item>
+        <item>@integer/page_option_value_page_range</item>
+    </integer-array>
+
+</resources>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 8b4b40a..27540d7 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -16,74 +16,50 @@
 
 <resources>
 
-    <!-- Title of the PrintSpooler application. [CHAR LIMIT=16] -->
+    <!-- Title of the PrintSpooler application. [CHAR LIMIT=50] -->
     <string name="app_label">Print Spooler</string>
 
-    <!-- Title of the print dialog. [CHAR LIMIT=10] -->
-    <string name="print_job_config_dialog_title">Print</string>
-
     <!-- Label of the print dialog's print button. [CHAR LIMIT=16] -->
-    <string name="print_button">Print</string>
+    <string name="print_button">PRINT</string>
 
-    <!-- Label of the print dialog's cancel button. [CHAR LIMIT=16] -->
-    <string name="cancel_button">Cancel</string>
+    <!-- Label of the destination widget. [CHAR LIMIT=20] -->
+    <string name="label_destination">DESTIINATION</string>
 
-    <!-- Label of the destination spinner. [CHAR LIMIT=16] -->
-    <string name="label_destination">Destination</string>
+    <!-- Label of the copies count widget. [CHAR LIMIT=20] -->
+    <string name="label_copies">COPIES</string>
 
-    <!-- Label of the copies count edit text. [CHAR LIMIT=16] -->
-    <string name="label_copies">Copies</string>
+    <!-- Label of the paper size widget. [CHAR LIMIT=20] -->
+    <string name="label_paper_size">PAPER SIZE</string>
 
-    <!-- Label of the media size spinner. [CHAR LIMIT=16] -->
-    <string name="label_media_size">Media size</string>
+    <!-- Label of the color mode widget. [CHAR LIMIT=20] -->
+    <string name="label_color">COLOR</string>
 
-    <!-- Label of the resolution spinner. [CHAR LIMIT=16] -->
-    <string name="label_resolution">Resolution</string>
+    <!-- Label of the orientation widget. [CHAR LIMIT=20] -->
+    <string name="label_orientation">ORIENTATION</string>
 
-    <!-- Label of the input tray spinner. [CHAR LIMIT=16] -->
-    <string name="label_input_tray">Input tray</string>
+    <!-- Label of the page selection widget. [CHAR LIMIT=20] -->
+    <string name="label_pages">PAGES</string>
 
-    <!-- Label of the output tray spinner. [CHAR LIMIT=16] -->
-    <string name="label_output_tray">Output tray</string>
+    <!-- Page range exmple used as a hint of how to specify such. [CHAR LIMIT=15] -->
+    <string name="pages_range_example">e.g. 1&#8211;5, 8</string>
 
-    <!-- Label of the duplex mode spinner. [CHAR LIMIT=16] -->
-    <string name="label_duplex_mode">Duplex mode</string>
+    <!-- Title for the pring preview button .[CHAR LIMIT=30] -->
+    <string name="print_preview">Print preview</string>
 
-    <!-- Label of the color mode spinner. [CHAR LIMIT=16] -->
-    <string name="label_color_mode">Color mode</string>
+    <!-- Title for the pring preview button if there is no PDF viewer isntalled. [CHAR LIMIT=50] -->
+    <string name="install_for_print_preview">Install PDF viewer for preview</string>
 
-    <!-- Label of the fitting mode spinner. [CHAR LIMIT=16] -->
-    <string name="label_fitting_mode">Fitting mode</string>
-
-    <!-- Label of the orientation spinner. [CHAR LIMIT=16] -->
-    <string name="label_orientation">Orientation</string>
-
-    <!-- Duplex mode labels. -->
-    <string-array name="duplex_mode_labels">
-        <!-- Duplex mode label: No duplexing. [CHAR LIMIT=20] -->
-        <item>None</item>
-        <!-- Duplex mode label: Turn a page along its long edge, e.g. like a book. [CHAR LIMIT=20] -->
-        <item>Long edge</item>
-        <!-- Duplex mode label: Turn a page along its short edge, e.g. like a notepad. [CHAR LIMIT=20] -->
-        <item>Short edge</item>
-    </string-array>
+    <!-- Title of the message that the printing application crashed. [CHAR LIMIT=50] -->
+    <string name="printing_app_crashed">Printing app crashed</string>
 
     <!-- Color mode labels. -->
     <string-array name="color_mode_labels">
         <!-- Color modelabel: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] -->
-        <item>Monochrome</item>
+        <item>Black &amp; White</item>
         <!-- Color mode label: Color color scheme, e.g. many colors are used. [CHAR LIMIT=20] -->
         <item>Color</item>
     </string-array>
 
-    <!-- Fitting mode labels. -->
-    <string-array name="fitting_mode_labels">
-        <!-- Fitting mode label: No fitting. [CHAR LIMIT=30] -->
-        <item>None</item>
-        <!-- Fitting mode label: Fit the content to the page. [CHAR LIMIT=30] -->
-        <item>Fit to page</item>
-    </string-array>
-
     <!-- Orientation labels. -->
     <string-array name="orientation_labels">
         <!-- Orientation label: Portrait page orientation. [CHAR LIMIT=30] -->
@@ -92,6 +68,14 @@
         <item>Landscape</item>
     </string-array>
 
+    <!-- Page options labels. -->
+    <string-array name="page_options_labels">
+        <!-- Page range option label: Print all pages [CHAR LIMIT=30] -->
+        <item>All</item>
+        <!-- Page range option label: Print a page range [CHAR LIMIT=30] -->
+        <item>Range</item>
+    </string-array>
+
     <!-- Title of an application permission, listed so the user can choose
          whether they want to allow the application to do this. -->
     <string name="permlab_bindPrintSpoolerService">bind to a print spooler service</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index c0faed8..1e1cc24 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -17,7 +17,13 @@
 package com.android.printspooler;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -34,8 +40,6 @@
 import android.print.PageRange;
 import android.print.PrintAttributes;
 import android.print.PrintAttributes.MediaSize;
-import android.print.PrintAttributes.Resolution;
-import android.print.PrintAttributes.Tray;
 import android.print.PrintDocumentAdapter.LayoutResultCallback;
 import android.print.PrintDocumentAdapter.WriteResultCallback;
 import android.print.PrintDocumentInfo;
@@ -43,25 +47,29 @@
 import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.text.Editable;
-import android.text.InputFilter;
-import android.text.Spanned;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Choreographer;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.ArrayAdapter;
+import android.widget.Button;
 import android.widget.EditText;
 import android.widget.Spinner;
+import android.widget.TextView;
 
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Activity for configuring a print job.
@@ -79,139 +87,38 @@
 
     private static final int MIN_COPIES = 1;
 
+    private static final Pattern PATTERN_DIGITS = Pattern.compile("\\d");
+
+    private static final Pattern PATTERN_ESCAPE_SPECIAL_CHARS = Pattern.compile(
+            "(?=[]\\[+&|!(){}^\"~*?:\\\\])");
+
+    private static final Pattern PATTERN_PAGE_RANGE = Pattern.compile(
+            "([0-9]+[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*[,]?[\\s]*)+");
+
     private final PrintSpooler mPrintSpooler = PrintSpooler.getInstance(this);
 
+    private Handler mHandler;
+
+    private Editor mEditor;
+
     private IPrinterDiscoveryObserver mPrinterDiscoveryObserver;
 
     private int mAppId;
     private int mPrintJobId;
 
-    private PrintAttributes mPrintAttributes;
+    private final PrintAttributes mOldPrintAttributes = new PrintAttributes.Builder().create();
+    private final PrintAttributes mCurrPrintAttributes = new PrintAttributes.Builder().create();
+    private final PrintAttributes mTempPrintAttributes = new PrintAttributes.Builder().create();
 
     private RemotePrintDocumentAdapter mRemotePrintAdapter;
 
-    // UI elements
-
-    private EditText mCopiesEditText;
-
-    private Spinner mDestinationSpinner;
-    public ArrayAdapter<SpinnerItem<PrinterInfo>> mDestinationSpinnerAdapter;
-
-    private Spinner mMediaSizeSpinner;
-    public ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
-
-    private Spinner mResolutionSpinner;
-    public ArrayAdapter<SpinnerItem<Resolution>> mResolutionSpinnerAdapter;
-
-    private Spinner mInputTraySpinner;
-    public ArrayAdapter<SpinnerItem<Tray>> mInputTraySpinnerAdapter;
-
-    private Spinner mOutputTraySpinner;
-    public ArrayAdapter<SpinnerItem<Tray>> mOutputTraySpinnerAdapter;
-
-    private Spinner mDuplexModeSpinner;
-    public ArrayAdapter<SpinnerItem<Integer>> mDuplexModeSpinnerAdapter;
-
-    private Spinner mColorModeSpinner;
-    public ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
-
-    private Spinner mFittingModeSpinner;
-    public ArrayAdapter<SpinnerItem<Integer>> mFittingModeSpinnerAdapter;
-
-    private Spinner mOrientationSpinner;
-    public ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
-
     private boolean mPrintConfirmed;
 
     private boolean mStarted;
 
     private IBinder mIPrintDocumentAdapter;
 
-    // TODO: Implement store/restore state.
-
-    private final OnItemSelectedListener mOnItemSelectedListener =
-            new AdapterView.OnItemSelectedListener() {
-        @Override
-        public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
-            if (spinner == mDestinationSpinner) {
-                updateUi();
-                notifyPrintableStartIfNeeded();
-            } else if (spinner == mMediaSizeSpinner) {
-                SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
-                mPrintAttributes.setMediaSize(mediaItem.value);
-                updatePrintableContentIfNeeded();
-            } else if (spinner == mResolutionSpinner) {
-                SpinnerItem<Resolution> resolutionItem =
-                        mResolutionSpinnerAdapter.getItem(position);
-                mPrintAttributes.setResolution(resolutionItem.value);
-                updatePrintableContentIfNeeded();
-            } else if (spinner == mInputTraySpinner) {
-                SpinnerItem<Tray> inputTrayItem =
-                        mInputTraySpinnerAdapter.getItem(position);
-                mPrintAttributes.setInputTray(inputTrayItem.value);
-            } else if (spinner == mOutputTraySpinner) {
-                SpinnerItem<Tray> outputTrayItem =
-                        mOutputTraySpinnerAdapter.getItem(position);
-                mPrintAttributes.setOutputTray(outputTrayItem.value);
-            } else if (spinner == mDuplexModeSpinner) {
-                SpinnerItem<Integer> duplexModeItem =
-                        mDuplexModeSpinnerAdapter.getItem(position);
-                mPrintAttributes.setDuplexMode(duplexModeItem.value);
-            } else if (spinner == mColorModeSpinner) {
-                SpinnerItem<Integer> colorModeItem =
-                        mColorModeSpinnerAdapter.getItem(position);
-                mPrintAttributes.setColorMode(colorModeItem.value);
-            } else if (spinner == mFittingModeSpinner) {
-                SpinnerItem<Integer> fittingModeItem =
-                        mFittingModeSpinnerAdapter.getItem(position);
-                mPrintAttributes.setFittingMode(fittingModeItem.value);
-            } else if (spinner == mOrientationSpinner) {
-                SpinnerItem<Integer> orientationItem =
-                        mOrientationSpinnerAdapter.getItem(position);
-                mPrintAttributes.setOrientation(orientationItem.value);
-            }
-        }
-
-        @Override
-        public void onNothingSelected(AdapterView<?> parent) {
-            /* do nothing*/
-        }
-    };
-
-    private final TextWatcher mTextWatcher = new TextWatcher() {
-        @Override
-        public void onTextChanged(CharSequence s, int start, int before, int count) {
-            final int copies = Integer.parseInt(mCopiesEditText.getText().toString());
-            mPrintAttributes.setCopies(copies);
-        }
-
-        @Override
-        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-            /* do nothing */
-        }
-
-        @Override
-        public void afterTextChanged(Editable s) {
-            /* do nothing */
-        }
-    };
-
-    private final InputFilter mInputFilter = new InputFilter() {
-        @Override
-        public CharSequence filter(CharSequence source, int start, int end,
-                Spanned dest, int dstart, int dend) {
-            StringBuffer text = new StringBuffer(dest.toString());
-            text.replace(dstart, dend, source.subSequence(start, end).toString());
-            if (TextUtils.isEmpty(text)) {
-                return dest;
-            }
-            final int copies = Integer.parseInt(text.toString());
-            if (copies < MIN_COPIES) {
-                return dest;
-            }
-            return null;
-        }
-    };
+    private PrintDocumentInfo mPrintDocumentInfo;
 
     private final DeathRecipient mDeathRecipient = new DeathRecipient() {
         @Override
@@ -221,6 +128,12 @@
     };
 
     @Override
+    protected void onDestroy() {
+        mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
+        super.onDestroy();
+    }
+
+    @Override
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
         setContentView(R.layout.print_job_config_activity);
@@ -228,265 +141,8 @@
         getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
                 | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
 
-        Bundle extras = getIntent().getExtras();
-
-        mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
-        if (mPrintJobId < 0) {
-            throw new IllegalArgumentException("Invalid print job id: " + mPrintJobId);
-        }
-
-        mAppId = extras.getInt(EXTRA_APP_ID, -1);
-        if (mAppId < 0) {
-            throw new IllegalArgumentException("Invalid app id: " + mAppId);
-        }
-
-        mPrintAttributes = getIntent().getParcelableExtra(EXTRA_ATTRIBUTES);
-        if (mPrintAttributes == null) {
-            mPrintAttributes = new PrintAttributes.Builder().create();
-        }
-
-        mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINTABLE);
-        if (mIPrintDocumentAdapter == null) {
-            throw new IllegalArgumentException("Printable cannot be null");
-        }
-        mRemotePrintAdapter = new RemotePrintDocumentAdapter(
-                IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
-                mPrintSpooler.generateFileForPrintJob(mPrintJobId));
-
-        try {
-            mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
-        } catch (RemoteException re) {
-            finish();
-        }
-
-        mPrinterDiscoveryObserver = new PrintDiscoveryObserver(getMainLooper());
-
-        bindUi();
-    }
-
-    @Override
-    protected void onDestroy() {
-        mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
-        super.onDestroy();
-    }
-
-    private void bindUi() {
-        // Copies
-        mCopiesEditText = (EditText) findViewById(R.id.copies_edittext);
-        mCopiesEditText.setText(String.valueOf(MIN_COPIES));
-        mCopiesEditText.addTextChangedListener(mTextWatcher);
-        mCopiesEditText.setFilters(new InputFilter[] {mInputFilter});
-
-        // Destination.
-        mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
-        mDestinationSpinnerAdapter = new ArrayAdapter<SpinnerItem<PrinterInfo>>(this,
-                android.R.layout.simple_spinner_dropdown_item);
-        mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
-        mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
-        // Media size.
-        mMediaSizeSpinner = (Spinner) findViewById(R.id.media_size_spinner);
-        mMediaSizeSpinnerAdapter = new ArrayAdapter<SpinnerItem<MediaSize>>(this,
-                android.R.layout.simple_spinner_dropdown_item);
-        mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter);
-        mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
-        // Resolution.
-        mResolutionSpinner = (Spinner) findViewById(R.id.resolution_spinner);
-        mResolutionSpinnerAdapter = new ArrayAdapter<SpinnerItem<Resolution>>(this,
-                android.R.layout.simple_spinner_dropdown_item);
-        mResolutionSpinner.setAdapter(mResolutionSpinnerAdapter);
-        mResolutionSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
-        // Input tray.
-        mInputTraySpinner = (Spinner) findViewById(R.id.input_tray_spinner);
-        mInputTraySpinnerAdapter = new ArrayAdapter<SpinnerItem<Tray>>(this,
-                android.R.layout.simple_spinner_dropdown_item);
-        mInputTraySpinner.setAdapter(mInputTraySpinnerAdapter);
-
-        // Output tray.
-        mOutputTraySpinner = (Spinner) findViewById(R.id.output_tray_spinner);
-        mOutputTraySpinnerAdapter = new ArrayAdapter<SpinnerItem<Tray>>(this,
-                android.R.layout.simple_spinner_dropdown_item);
-        mOutputTraySpinner.setAdapter(mOutputTraySpinnerAdapter);
-        mOutputTraySpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
-        // Duplex mode.
-        mDuplexModeSpinner = (Spinner) findViewById(R.id.duplex_mode_spinner);
-        mDuplexModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this,
-                android.R.layout.simple_spinner_dropdown_item);
-        mDuplexModeSpinner.setAdapter(mDuplexModeSpinnerAdapter);
-        mDuplexModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
-        // Color mode.
-        mColorModeSpinner = (Spinner) findViewById(R.id.color_mode_spinner);
-        mColorModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this,
-                android.R.layout.simple_spinner_dropdown_item);
-        mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
-        mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
-        // Color mode.
-        mFittingModeSpinner = (Spinner) findViewById(R.id.fitting_mode_spinner);
-        mFittingModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this,
-                android.R.layout.simple_spinner_dropdown_item);
-        mFittingModeSpinner.setAdapter(mFittingModeSpinnerAdapter);
-        mFittingModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-
-        // Orientation
-        mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner);
-        mOrientationSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(this,
-                android.R.layout.simple_spinner_dropdown_item);
-        mOrientationSpinner.setAdapter(mOrientationSpinnerAdapter);
-        mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-    }
-
-    private void updateUi() {
-        final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
-        PrinterInfo printer = mDestinationSpinnerAdapter.getItem(selectedIndex).value;
-        printer.getDefaults(mPrintAttributes);
-
-        // Copies.
-        mCopiesEditText.setText(String.valueOf(
-                Math.max(mPrintAttributes.getCopies(), MIN_COPIES)));
-
-        // Media size.
-        mMediaSizeSpinnerAdapter.clear();
-        List<MediaSize> mediaSizes = printer.getMediaSizes();
-        final int mediaSizeCount = mediaSizes.size();
-        for (int i = 0; i < mediaSizeCount; i++) {
-            MediaSize mediaSize = mediaSizes.get(i);
-            mMediaSizeSpinnerAdapter.add(new SpinnerItem<MediaSize>(
-                    mediaSize, mediaSize.getLabel()));
-        }
-        final int selectedMediaSizeIndex = mediaSizes.indexOf(
-                mPrintAttributes.getMediaSize());
-        mMediaSizeSpinner.setOnItemSelectedListener(null);
-        mMediaSizeSpinner.setSelection(selectedMediaSizeIndex);
-
-        // Resolution.
-        mResolutionSpinnerAdapter.clear();
-        List<Resolution> resolutions = printer.getResolutions();
-        final int resolutionCount = resolutions.size();
-        for (int i = 0; i < resolutionCount; i++) {
-            Resolution resolution = resolutions.get(i);
-            mResolutionSpinnerAdapter.add(new SpinnerItem<Resolution>(
-                    resolution, resolution.getLabel(getPackageManager())));
-        }
-        final int selectedResolutionIndex = resolutions.indexOf(
-                mPrintAttributes.getResolution());
-        mResolutionSpinner.setOnItemSelectedListener(null);
-        mResolutionSpinner.setSelection(selectedResolutionIndex);
-
-        // AdapterView has the weird behavior to notify the selection listener for a
-        // selection event that occurred *before* the listener was registered because
-        // it does the real selection change on the next layout pass. To avoid this
-        // behavior we re-attach the listener in the next traversal window - fun!
-        Choreographer.getInstance().postCallback(
-                Choreographer.CALLBACK_TRAVERSAL, new Runnable() {
-                    @Override
-                    public void run() {
-                        mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-                        mResolutionSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
-                    }
-                }, null);
-
-        // Input tray.
-        mInputTraySpinnerAdapter.clear();
-        List<Tray> inputTrays = printer.getInputTrays();
-        if (inputTrays != null) {
-            final int inputTrayCount = inputTrays.size();
-            for (int i = 0; i < inputTrayCount; i++) {
-                Tray inputTray = inputTrays.get(i);
-                mInputTraySpinnerAdapter.add(new SpinnerItem<Tray>(
-                        inputTray, inputTray.getLabel(getPackageManager())));
-            }
-            final int selectedInputTrayIndex = inputTrays.indexOf(
-                    mPrintAttributes.getInputTray());
-            mInputTraySpinner.setSelection(selectedInputTrayIndex);
-        }
-
-        // Output tray.
-        mOutputTraySpinnerAdapter.clear();
-        List<Tray> outputTrays = printer.getOutputTrays();
-        if (outputTrays != null) {
-            final int outputTrayCount = outputTrays.size();
-            for (int i = 0; i < outputTrayCount; i++) {
-                Tray outputTray = outputTrays.get(i);
-                mOutputTraySpinnerAdapter.add(new SpinnerItem<Tray>(
-                        outputTray, outputTray.getLabel(getPackageManager())));
-            }
-            final int selectedOutputTrayIndex = outputTrays.indexOf(
-                    mPrintAttributes.getOutputTray());
-            mOutputTraySpinner.setSelection(selectedOutputTrayIndex);
-        }
-
-        // Duplex mode.
-        final int duplexModes = printer.getDuplexModes();
-        mDuplexModeSpinnerAdapter.clear();
-        String[] duplexModeLabels = getResources().getStringArray(
-                R.array.duplex_mode_labels);
-        int remainingDuplexModes = duplexModes;
-        while (remainingDuplexModes != 0) {
-            final int duplexBitOffset = Integer.numberOfTrailingZeros(remainingDuplexModes);
-            final int duplexMode = 1 << duplexBitOffset;
-            remainingDuplexModes &= ~duplexMode;
-            mDuplexModeSpinnerAdapter.add(new SpinnerItem<Integer>(duplexMode,
-                    duplexModeLabels[duplexBitOffset]));
-        }
-        final int selectedDuplexModeIndex = Integer.numberOfTrailingZeros(
-                (duplexModes & mPrintAttributes.getDuplexMode()));
-        mDuplexModeSpinner.setSelection(selectedDuplexModeIndex);
-
-        // Color mode.
-        final int colorModes = printer.getColorModes();
-        mColorModeSpinnerAdapter.clear();
-        String[] colorModeLabels = getResources().getStringArray(
-                R.array.color_mode_labels);
-        int remainingColorModes = colorModes;
-        while (remainingColorModes != 0) {
-            final int colorBitOffset = Integer.numberOfTrailingZeros(remainingColorModes);
-            final int colorMode = 1 << colorBitOffset;
-            remainingColorModes &= ~colorMode;
-            mColorModeSpinnerAdapter.add(new SpinnerItem<Integer>(colorMode,
-                    colorModeLabels[colorBitOffset]));
-        }
-        final int selectedColorModeIndex = Integer.numberOfTrailingZeros(
-                (colorModes & mPrintAttributes.getColorMode()));
-        mColorModeSpinner.setSelection(selectedColorModeIndex);
-
-        // Fitting mode.
-        final int fittingModes = printer.getFittingModes();
-        mFittingModeSpinnerAdapter.clear();
-        String[] fittingModeLabels = getResources().getStringArray(
-                R.array.fitting_mode_labels);
-        int remainingFittingModes = fittingModes;
-        while (remainingFittingModes != 0) {
-            final int fittingBitOffset = Integer.numberOfTrailingZeros(remainingFittingModes);
-            final int fittingMode = 1 << fittingBitOffset;
-            remainingFittingModes &= ~fittingMode;
-            mFittingModeSpinnerAdapter.add(new SpinnerItem<Integer>(fittingMode,
-                    fittingModeLabels[fittingBitOffset]));
-        }
-        final int selectedFittingModeIndex = Integer.numberOfTrailingZeros(
-                (fittingModes & mPrintAttributes.getFittingMode()));
-        mFittingModeSpinner.setSelection(selectedFittingModeIndex);
-
-        // Orientation.
-        final int orientations = printer.getOrientations();
-        mOrientationSpinnerAdapter.clear();
-        String[] orientationLabels = getResources().getStringArray(
-                R.array.orientation_labels);
-        int remainingOrientations = orientations;
-        while (remainingOrientations != 0) {
-            final int orientationBitOffset = Integer.numberOfTrailingZeros(remainingOrientations);
-            final int orientation = 1 << orientationBitOffset;
-            remainingOrientations &= ~orientation;
-            mOrientationSpinnerAdapter.add(new SpinnerItem<Integer>(orientation,
-                    orientationLabels[orientationBitOffset]));
-        }
-        final int selectedOrientationIndex = Integer.numberOfTrailingZeros(
-                (orientations & mPrintAttributes.getOrientation()));
-        mOrientationSpinner.setSelection(selectedOrientationIndex);
+        mHandler = new MyHandler(Looper.getMainLooper());
+        mEditor = new Editor();
     }
 
     @Override
@@ -503,29 +159,13 @@
         notifyPrintableFinishIfNeeded();
     }
 
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        getMenuInflater().inflate(R.menu.print_job_config_activity, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        if (item.getItemId() == R.id.print_button) {
-            mPrintConfirmed = true;
-            finish();
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
     private void notifyPrintableStartIfNeeded() {
-        if (mDestinationSpinner.getSelectedItemPosition() < 0
+        if (mEditor.getCurrentPrinter() == null
                 || mStarted) {
             return;
         }
         mStarted = true;
         mRemotePrintAdapter.start();
-        updatePrintableContentIfNeeded();
     }
 
     private void updatePrintableContentIfNeeded() {
@@ -533,43 +173,68 @@
             return;
         }
 
-        // TODO: Implement old attributes tracking
-        mPrintSpooler.setPrintJobAttributes(mPrintJobId, mPrintAttributes);
+        mPrintSpooler.setPrintJobAttributes(mPrintJobId, mCurrPrintAttributes);
+
+        mRemotePrintAdapter.cancel();
+        mHandler.removeMessages(MyHandler.MSG_ON_LAYOUT_FINISHED);
+        mHandler.removeMessages(MyHandler.MSG_ON_LAYOUT_FAILED);
 
         // TODO: Implement setting the print preview attribute
-        mRemotePrintAdapter.layout(new PrintAttributes.Builder().create(),
-                mPrintAttributes, new LayoutResultCallback() {
+        mRemotePrintAdapter.layout(mOldPrintAttributes,
+                mCurrPrintAttributes, new LayoutResultCallback() {
             @Override
             public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
-                // TODO: Handle the case of unchanged content
-                mPrintSpooler.setPrintJobPrintDocumentInfo(mPrintJobId, info);
-
-                // TODO: Implement page selector.
-                final List<PageRange> pages = new ArrayList<PageRange>();
-                pages.add(PageRange.ALL_PAGES);
-
-                mRemotePrintAdapter.write(pages, new WriteResultCallback() {
-                    @Override
-                    public void onWriteFinished(List<PageRange> pages) {
-                        updatePrintPreview(mRemotePrintAdapter.getFile());
-                    }
-
-                    @Override
-                    public void onWriteFailed(CharSequence error) {
-                        Log.e(LOG_TAG, "Error write layout: " + error);
-                        finishActivity(Activity.RESULT_CANCELED);
-                    }
-                });
+                mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FINISHED, changed ? 1 : 0,
+                        0, info).sendToTarget();
             }
 
             @Override
             public void onLayoutFailed(CharSequence error) {
-                Log.e(LOG_TAG, "Error during layout: " + error);
-                finishActivity(Activity.RESULT_CANCELED);
+                mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FAILED, error).sendToTarget();
             }
         }, new Bundle());
     }
 
+    private void handleOnLayoutFinished(PrintDocumentInfo info, boolean changed) {
+        mPrintDocumentInfo = info;
+
+        mEditor.updateUiIfNeeded();
+
+        // TODO: Handle the case of unchanged content
+        mPrintSpooler.setPrintJobPrintDocumentInfo(mPrintJobId, info);
+
+        // TODO: Implement page selector.
+        final List<PageRange> pages = new ArrayList<PageRange>();
+        pages.add(PageRange.ALL_PAGES);
+
+        mRemotePrintAdapter.write(pages, new WriteResultCallback() {
+            @Override
+            public void onWriteFinished(List<PageRange> pages) {
+                mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FINISHED, pages).sendToTarget();
+            }
+
+            @Override
+            public void onWriteFailed(CharSequence error) {
+                mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FAILED, error).sendToTarget();
+            }
+        });
+    }
+
+    private void handleOnLayoutFailed(CharSequence error) {
+        Log.e(LOG_TAG, "Error during layout: " + error);
+        finishActivity(Activity.RESULT_CANCELED);
+    }
+
+    private void handleOnWriteFinished(List<PageRange> pages) {
+        // TODO: Now we have to allow the preview button
+        mEditor.updatePrintPreview(mRemotePrintAdapter.getFile());
+    }
+
+    private void handleOnWriteFailed(CharSequence error) {
+        Log.e(LOG_TAG, "Error write layout: " + error);
+        finishActivity(Activity.RESULT_CANCELED);
+    }
+
     private void notifyPrintableFinishIfNeeded() {
         if (!mStarted) {
             return;
@@ -580,9 +245,9 @@
         }
         mRemotePrintAdapter.finish();
 
+        PrinterInfo printer = mEditor.getCurrentPrinter();
         // If canceled or no printer, nothing to do.
-        final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
-        if (!mPrintConfirmed || selectedIndex < 0) {
+        if (!mPrintConfirmed || printer == null) {
             // Update the print job's status.
             mPrintSpooler.setPrintJobState(mPrintJobId,
                     PrintJobInfo.STATE_CANCELED);
@@ -590,10 +255,7 @@
         }
 
         // Update the print job's printer.
-        SpinnerItem<PrinterInfo> printerItem =
-                mDestinationSpinnerAdapter.getItem(selectedIndex);
-        PrinterId printerId =  printerItem.value.getId();
-        mPrintSpooler.setPrintJobPrinterId(mPrintJobId, printerId);
+        mPrintSpooler.setPrintJobPrinterId(mPrintJobId, printer.getId());
 
         // Update the print job's status.
         mPrintSpooler.setPrintJobState(mPrintJobId,
@@ -610,50 +272,11 @@
         }
     }
 
-    private void updatePrintPreview(File file) {
-        // TODO: Implement
-    }
-
-    private void addPrinters(List<PrinterInfo> addedPrinters) {
-        final int addedPrinterCount = addedPrinters.size();
-        for (int i = 0; i < addedPrinterCount; i++) {
-            PrinterInfo addedPrinter = addedPrinters.get(i);
-            boolean duplicate = false;
-            final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
-            for (int j = 0; j < existingPrinterCount; j++) {
-                PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
-                if (addedPrinter.getId().equals(existingPrinter.getId())) {
-                    duplicate = true;
-                    break;
-                }
-            }
-            if (!duplicate) {
-                mDestinationSpinnerAdapter.add(new SpinnerItem<PrinterInfo>(
-                        addedPrinter, addedPrinter.getLabel()));
-            } else {
-                Log.w(LOG_TAG, "Skipping a duplicate printer: " + addedPrinter);
-            }
-        }
-    }
-
-    private void removePrinters(List<PrinterId> pritnerIds) {
-        final int printerIdCount = pritnerIds.size();
-        for (int i = 0; i < printerIdCount; i++) {
-            PrinterId removedPrinterId = pritnerIds.get(i);
-            boolean removed = false;
-            final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
-            for (int j = 0; j < existingPrinterCount; j++) {
-                PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
-                if (removedPrinterId.equals(existingPrinter.getId())) {
-                    mDestinationSpinnerAdapter.remove(mDestinationSpinnerAdapter.getItem(j));
-                    removed = true;
-                    break;
-                }
-            }
-            if (!removed) {
-                Log.w(LOG_TAG, "Ignoring not added printer with id: " + removedPrinterId);
-            }
-        }
+    private boolean hasPdfViewer() {
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.setType("application/pdf");
+        return !getPackageManager().queryIntentActivities(intent,
+                PackageManager.MATCH_DEFAULT_ONLY).isEmpty();
     }
 
     // Caution: Use this only for debugging
@@ -695,16 +318,11 @@
                     switch (message.what) {
                         case MESSAGE_ADD_DICOVERED_PRINTERS: {
                             List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
-                            addPrinters(printers);
-                            // Just added the first printer, so select it and start printing.
-                            if (mDestinationSpinnerAdapter.getCount() == 1) {
-                                mDestinationSpinner.setSelection(0);
-                            }
+                            mEditor.addPrinters(printers);
                         } break;
                         case MESSAGE_REMOVE_DICOVERED_PRINTERS: {
                             List<PrinterId> printerIds = (List<PrinterId>) message.obj;
-                            removePrinters(printerIds);
-                            // TODO: Handle removing the last printer.
+                            mEditor.removePrinters(printerIds);
                         } break;
                     }
                 }
@@ -735,4 +353,650 @@
             return label.toString();
         }
     }
+
+    /**
+     * An instance of this class class is intended to be the first focusable
+     * in a layout to which the system automatically gives focus. It performs
+     * some voodoo to avoid the first tap on it to start an edit mode, rather
+     * to bring up the IME, i.e. to get the behavior as if the view was not
+     * focused.
+     */
+    public static final class CustomEditText extends EditText {
+        private boolean mClickedBeforeFocus;
+
+        public CustomEditText(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @Override
+        public boolean performClick() {
+            super.performClick();
+            if (isFocused() && !mClickedBeforeFocus) {
+                clearFocus();
+                requestFocus();
+            }
+            mClickedBeforeFocus = true;
+            return true;
+        }
+
+        @Override
+        public void setError(CharSequence error, Drawable icon) {
+            setCompoundDrawables(null, null, icon, null);
+        }
+
+        protected void onFocusChanged(boolean gainFocus, int direction,
+                Rect previouslyFocusedRect) {
+            if (!gainFocus) {
+                mClickedBeforeFocus = false;
+            }
+            super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        }
+    }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_ON_LAYOUT_FINISHED = 1;
+        public static final int MSG_ON_LAYOUT_FAILED = 2;
+        public static final int MSG_ON_WRITE_FINISHED = 3;
+        public static final int MSG_ON_WRITE_FAILED = 4;
+
+        public MyHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_ON_LAYOUT_FINISHED: {
+                    PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
+                    final boolean changed = (message.arg1 == 1);
+                    handleOnLayoutFinished(info, changed);
+                } break;
+
+                case MSG_ON_LAYOUT_FAILED: {
+                    CharSequence error = (CharSequence) message.obj;
+                    handleOnLayoutFailed(error);
+                } break;
+
+                case MSG_ON_WRITE_FINISHED: {
+                    List<PageRange> pages = (List<PageRange>) message.obj;
+                    handleOnWriteFinished(pages);
+                } break;
+
+                case MSG_ON_WRITE_FAILED: {
+                    CharSequence error = (CharSequence) message.obj;
+                    handleOnWriteFailed(error);
+                } break;
+            }
+        }
+    }
+
+    private class Editor {
+        private EditText mCopiesEditText;
+
+        private EditText mRangeEditText;
+
+        private Spinner mDestinationSpinner;
+        public ArrayAdapter<SpinnerItem<PrinterInfo>> mDestinationSpinnerAdapter;
+
+        private Spinner mMediaSizeSpinner;
+        public ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
+
+        private Spinner mColorModeSpinner;
+        public ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
+
+        private Spinner mOrientationSpinner;
+        public ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
+
+        private Spinner mRangeOptionsSpinner;
+        public ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter;
+
+        private Button mPrintPreviewButton;
+
+        private Button mPrintButton;
+
+        private final OnItemSelectedListener mOnItemSelectedListener =
+                new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
+                if (spinner == mDestinationSpinner) {
+                    mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+                    mCurrPrintAttributes.clear();
+                    final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
+                    if (selectedIndex >= 0) {
+                        mDestinationSpinnerAdapter.getItem(selectedIndex).value.getDefaults(
+                                mCurrPrintAttributes);
+                    }
+                    updateUiIfNeeded();
+                    notifyPrintableStartIfNeeded();
+                    updatePrintableContentIfNeeded();
+                } else if (spinner == mMediaSizeSpinner) {
+                    SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
+                    mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+                    mCurrPrintAttributes.setMediaSize(mediaItem.value);
+                    updatePrintableContentIfNeeded();
+                } else if (spinner == mColorModeSpinner) {
+                    SpinnerItem<Integer> colorModeItem =
+                            mColorModeSpinnerAdapter.getItem(position);
+                    mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+                    mCurrPrintAttributes.setColorMode(colorModeItem.value);
+                    updatePrintableContentIfNeeded();
+                } else if (spinner == mOrientationSpinner) {
+                    SpinnerItem<Integer> orientationItem =
+                            mOrientationSpinnerAdapter.getItem(position);
+                    mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+                    mCurrPrintAttributes.setOrientation(orientationItem.value);
+                    updatePrintableContentIfNeeded();
+                } else if (spinner == mRangeOptionsSpinner) {
+                    updateUiIfNeeded();
+                    updatePrintableContentIfNeeded();
+                }
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+                /* do nothing*/
+            }
+        };
+
+        private final TextWatcher mCopiesTextWatcher = new TextWatcher() {
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+                /* do nothing */
+            }
+
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+                /* do nothing */
+            }
+
+            @Override
+            public void afterTextChanged(Editable editable) {
+                if (editable.length() == 0) {
+                    mCopiesEditText.setError("");
+                    mPrintButton.setEnabled(false);
+                    return;
+                }
+                final int copies = Integer.parseInt(editable.toString());
+                if (copies < MIN_COPIES) {
+                    mCopiesEditText.setError("");
+                    mPrintButton.setEnabled(false);
+                    return;
+                }
+                mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+                mCurrPrintAttributes.setCopies(copies);
+            }
+        };
+
+        private final TextWatcher mRangeTextWatcher = new TextWatcher() {
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {
+                /* do nothing */
+            }
+
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+                /* do nothing */
+            }
+
+            @Override
+            public void afterTextChanged(Editable editable) {
+                String text = editable.toString();
+
+                if (TextUtils.isEmpty(text)) {
+                    mRangeEditText.setError("");
+                    mPrintButton.setEnabled(false);
+                    return;
+                }
+
+                String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
+                if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
+                    mRangeEditText.setError("");
+                    mPrintButton.setEnabled(false);
+                    return;
+                }
+
+                Matcher matcher = PATTERN_DIGITS.matcher(text);
+                while (matcher.find()) {
+                    String numericString = text.substring(matcher.start(), matcher.end());
+                    final int pageIndex = Integer.parseInt(numericString);
+                    if (pageIndex < 1 || pageIndex > mPrintDocumentInfo.getPageCount()) {
+                        mRangeEditText.setError("");
+                        mPrintButton.setEnabled(false);
+                        return;
+                    }
+                }
+
+                mRangeEditText.setError(null);
+                mPrintButton.setEnabled(true);
+            }
+        };
+
+        public Editor() {
+            Bundle extras = getIntent().getExtras();
+
+            mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
+            if (mPrintJobId < 0) {
+                throw new IllegalArgumentException("Invalid print job id: " + mPrintJobId);
+            }
+
+            mAppId = extras.getInt(EXTRA_APP_ID, -1);
+            if (mAppId < 0) {
+                throw new IllegalArgumentException("Invalid app id: " + mAppId);
+            }
+
+            PrintAttributes attributes = getIntent().getParcelableExtra(EXTRA_ATTRIBUTES);
+            if (attributes == null) {
+                mCurrPrintAttributes.copyFrom(attributes);
+            }
+
+            mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINTABLE);
+            if (mIPrintDocumentAdapter == null) {
+                throw new IllegalArgumentException("Printable cannot be null");
+            }
+            mRemotePrintAdapter = new RemotePrintDocumentAdapter(
+                    IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
+                    mPrintSpooler.generateFileForPrintJob(mPrintJobId));
+
+            try {
+                mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
+            } catch (RemoteException re) {
+                finish();
+            }
+
+            mPrinterDiscoveryObserver = new PrintDiscoveryObserver(getMainLooper());
+
+            bindUi();
+        }
+
+        private void bindUi() {
+            // Copies
+            mCopiesEditText = (EditText) findViewById(R.id.copies_edittext);
+            mCopiesEditText.setText(String.valueOf(MIN_COPIES));
+            mCopiesEditText.addTextChangedListener(mCopiesTextWatcher);
+            mCopiesEditText.setText(String.valueOf(
+                    Math.max(mCurrPrintAttributes.getCopies(), MIN_COPIES)));
+            mCopiesEditText.selectAll();
+
+            // Destination.
+            mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
+            mDestinationSpinnerAdapter = new ArrayAdapter<SpinnerItem<PrinterInfo>>(
+                    PrintJobConfigActivity.this, R.layout.spinner_dropdown_item) {
+                        @Override
+                        public View getDropDownView(int position, View convertView,
+                                ViewGroup parent) {
+                            return getView(position, convertView, parent);
+                        }
+
+                        @Override
+                        public View getView(int position, View convertView, ViewGroup parent) {
+                            if (convertView == null) {
+                                convertView = getLayoutInflater().inflate(
+                                        R.layout.spinner_dropdown_item, parent, false);
+                            }
+
+                            PrinterInfo printerInfo = getItem(position).value;
+                            TextView title = (TextView) convertView.findViewById(R.id.title);
+                            title.setText(printerInfo.getLabel());
+
+                            try {
+                                TextView subtitle = (TextView)
+                                        convertView.findViewById(R.id.subtitle);
+                                PackageManager pm = getPackageManager();
+                                PackageInfo packageInfo = pm.getPackageInfo(
+                                        printerInfo.getId().getService().getPackageName(), 0);
+                                subtitle.setText(packageInfo.applicationInfo.loadLabel(pm));
+                                subtitle.setVisibility(View.VISIBLE);
+                            } catch (NameNotFoundException nnfe) {
+                                /* ignore */
+                            }
+
+                            return convertView;
+                        }
+            };
+            mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
+            mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+
+            // Media size.
+            mMediaSizeSpinner = (Spinner) findViewById(R.id.paper_size_spinner);
+            mMediaSizeSpinnerAdapter = new ArrayAdapter<SpinnerItem<MediaSize>>(
+                    PrintJobConfigActivity.this,
+                    R.layout.spinner_dropdown_item, R.id.title);
+            mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter);
+            mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+
+            // Color mode.
+            mColorModeSpinner = (Spinner) findViewById(R.id.color_spinner);
+            mColorModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
+                    PrintJobConfigActivity.this,
+                    R.layout.spinner_dropdown_item, R.id.title);
+            mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
+            mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+
+            // Orientation
+            mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner);
+            mOrientationSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
+                    PrintJobConfigActivity.this,
+                    R.layout.spinner_dropdown_item, R.id.title);
+            mOrientationSpinner.setAdapter(mOrientationSpinnerAdapter);
+            mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+
+            // Range
+            mRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
+            mRangeEditText.addTextChangedListener(mRangeTextWatcher);
+
+            // Range options
+            mRangeOptionsSpinner = (Spinner) findViewById(R.id.range_options_spinner);
+            mRangeOptionsSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
+                    PrintJobConfigActivity.this,
+                    R.layout.spinner_dropdown_item, R.id.title);
+            mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter);
+            mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+            final int[] rangeOptionsValues = getResources().getIntArray(
+                    R.array.page_options_values);
+            String[] rangeOptionsLabels = getResources().getStringArray(
+                    R.array.page_options_labels);
+            final int rangeOptionsCount = rangeOptionsLabels.length;
+            for (int i = 0; i < rangeOptionsCount; i++) {
+                mRangeOptionsSpinnerAdapter.add(new SpinnerItem<Integer>(
+                        rangeOptionsValues[i], rangeOptionsLabels[i]));
+            }
+            mRangeOptionsSpinner.setSelection(0);
+
+            mPrintPreviewButton = (Button) findViewById(R.id.print_preview_button);
+            mPrintPreviewButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    // TODO: Implement
+                }
+            });
+
+            mPrintButton = (Button) findViewById(R.id.print_button);
+            mPrintButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mPrintConfirmed = true;
+                    finish();
+                }
+            });
+        }
+
+        private void updateUiIfNeeded() {
+            final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
+
+            if (selectedIndex < 0) {
+                // Destination
+                mDestinationSpinner.setEnabled(false);
+
+                // Copies
+                mCopiesEditText.setText("1");
+                mCopiesEditText.setEnabled(false);
+
+                // Media size
+                mMediaSizeSpinner.setOnItemSelectedListener(null);
+                mMediaSizeSpinner.setSelection(AdapterView.INVALID_POSITION);
+                mMediaSizeSpinner.setEnabled(false);
+
+                // Color mode
+                mColorModeSpinner.setOnItemSelectedListener(null);
+                mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION);
+                mColorModeSpinner.setEnabled(false);
+
+                // Orientation
+                mOrientationSpinner.setOnItemSelectedListener(null);
+                mOrientationSpinner.setSelection(AdapterView.INVALID_POSITION);
+                mOrientationSpinner.setEnabled(false);
+
+                // Range
+                mRangeOptionsSpinner.setOnItemSelectedListener(null);
+                mRangeOptionsSpinner.setSelection(0);
+                mRangeOptionsSpinner.setEnabled(false);
+                mRangeEditText.setText("");
+                mRangeEditText.setEnabled(false);
+                mRangeEditText.setVisibility(View.INVISIBLE);
+
+                // Print preview
+                mPrintPreviewButton.setEnabled(false);
+                mPrintPreviewButton.setText(getString(R.string.print_preview));
+
+                // Print
+                mPrintButton.setEnabled(false);
+            } else {
+                PrintAttributes defaultAttributes = mTempPrintAttributes;
+                PrinterInfo printer = mDestinationSpinnerAdapter.getItem(selectedIndex).value;
+                printer.getDefaults(defaultAttributes);
+
+                // Destination
+                mDestinationSpinner.setEnabled(true);
+
+                // Copies
+                mCopiesEditText.setEnabled(true);
+
+                // Media size.
+                List<MediaSize> mediaSizes = printer.getMediaSizes();
+                boolean mediaSizesChanged = false;
+                final int mediaSizeCount = mediaSizes.size();
+                if (mediaSizeCount != mMediaSizeSpinnerAdapter.getCount()) {
+                    mediaSizesChanged = true;
+                } else {
+                    for (int i = 0; i < mediaSizeCount; i++) {
+                        if (!mediaSizes.get(i).equals(mMediaSizeSpinnerAdapter.getItem(i).value)) {
+                            mediaSizesChanged = true;
+                            break;
+                        }
+                    }
+                }
+                if (mediaSizesChanged) {
+                    mMediaSizeSpinnerAdapter.clear();
+                    for (int i = 0; i < mediaSizeCount; i++) {
+                        MediaSize mediaSize = mediaSizes.get(i);
+                        mMediaSizeSpinnerAdapter.add(new SpinnerItem<MediaSize>(
+                                mediaSize, mediaSize.getLabel()));
+                    }
+                    if (mediaSizeCount > 0) {
+                        mMediaSizeSpinner.setEnabled(true);
+                        final int selectedMediaSizeIndex = Math.max(mediaSizes.indexOf(
+                                defaultAttributes.getMediaSize()), 0);
+                        mMediaSizeSpinner.setOnItemSelectedListener(null);
+                        mMediaSizeSpinner.setSelection(selectedMediaSizeIndex);
+                    }
+                }
+
+                // Color mode.
+                final int colorModes = printer.getColorModes();
+                boolean colorModesChanged = false;
+                if (Integer.bitCount(colorModes) != mColorModeSpinnerAdapter.getCount()) {
+                    colorModesChanged = true;
+                } else {
+                    int remainingColorModes = colorModes;
+                    while (remainingColorModes != 0) {
+                        final int colorBitOffset = Integer.numberOfTrailingZeros(
+                                remainingColorModes);
+                        final int colorMode = 1 << colorBitOffset;
+                        remainingColorModes &= ~colorMode;
+                        if (colorMode != mColorModeSpinnerAdapter.getItem(colorBitOffset).value) {
+                            colorModesChanged = true;
+                            break;
+                        }
+                    }
+                }
+                if (colorModesChanged) {
+                    mColorModeSpinnerAdapter.clear();
+                    String[] colorModeLabels = getResources().getStringArray(
+                            R.array.color_mode_labels);
+                    int remainingColorModes = colorModes;
+                    while (remainingColorModes != 0) {
+                        final int colorBitOffset = Integer.numberOfTrailingZeros(
+                                remainingColorModes);
+                        final int colorMode = 1 << colorBitOffset;
+                        remainingColorModes &= ~colorMode;
+                        mColorModeSpinnerAdapter.add(new SpinnerItem<Integer>(colorMode,
+                                colorModeLabels[colorBitOffset]));
+                    }
+                    if (colorModes > 0) {
+                        mColorModeSpinner.setEnabled(true);
+                        final int selectedColorModeIndex = Integer.numberOfTrailingZeros(
+                                (colorModes & defaultAttributes.getColorMode()));
+                        mColorModeSpinner.setOnItemSelectedListener(null);
+                        mColorModeSpinner.setSelection(selectedColorModeIndex);
+                    }
+                }
+
+                // Orientation.
+                final int orientations = printer.getOrientations();
+                boolean orientationsChanged = false;
+                if (Integer.bitCount(orientations) != mOrientationSpinnerAdapter.getCount()) {
+                    orientationsChanged = true;
+                } else {
+                    int remainingOrientations = orientations;
+                    while (remainingOrientations != 0) {
+                        final int orientationBitOffset = Integer.numberOfTrailingZeros(
+                                remainingOrientations);
+                        final int orientation = 1 << orientationBitOffset;
+                        remainingOrientations &= ~orientation;
+                        if (orientation != mOrientationSpinnerAdapter.getItem(
+                                orientationBitOffset).value) {
+                            orientationsChanged = true;
+                            break;
+                        }
+                    }
+                }
+                if (orientationsChanged) {
+                    mOrientationSpinnerAdapter.clear();
+                    String[] orientationLabels = getResources().getStringArray(
+                            R.array.orientation_labels);
+                    int remainingOrientations = orientations;
+                    while (remainingOrientations != 0) {
+                        final int orientationBitOffset = Integer.numberOfTrailingZeros(
+                                remainingOrientations);
+                        final int orientation = 1 << orientationBitOffset;
+                        remainingOrientations &= ~orientation;
+                        mOrientationSpinnerAdapter.add(new SpinnerItem<Integer>(orientation,
+                                orientationLabels[orientationBitOffset]));
+                    }
+                    if (orientations > 0) {
+                        mOrientationSpinner.setEnabled(true);
+                        final int selectedOrientationIndex = Integer.numberOfTrailingZeros(
+                                (orientations & defaultAttributes.getOrientation()));
+                        mOrientationSpinner.setOnItemSelectedListener(null);
+                        mOrientationSpinner.setSelection(selectedOrientationIndex);
+                    }
+                }
+
+                // Range options
+                if (mPrintDocumentInfo != null && (mPrintDocumentInfo.getPageCount() > 1
+                        || mPrintDocumentInfo.getPageCount()
+                            == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)) {
+                    mRangeOptionsSpinner.setEnabled(true);
+                    if (mRangeOptionsSpinner.getSelectedItemPosition() > 0
+                            && !mRangeEditText.isEnabled()) {
+                        mRangeEditText.setEnabled(true);
+                        mRangeEditText.setError("");
+                        mRangeEditText.setVisibility(View.VISIBLE);
+                        mRangeEditText.requestFocus();
+                        InputMethodManager imm = (InputMethodManager)
+                                getSystemService(INPUT_METHOD_SERVICE);
+                        imm.showSoftInput(mRangeEditText, 0);
+                    }
+                } else {
+                    mRangeOptionsSpinner.setOnItemSelectedListener(null);
+                    mRangeOptionsSpinner.setSelection(0);
+                    mRangeOptionsSpinner.setEnabled(false);
+                    mRangeEditText.setEnabled(false);
+                    mRangeEditText.setText("");
+                    mRangeEditText.setVisibility(View.INVISIBLE);
+                }
+
+                // Print preview
+                mPrintPreviewButton.setEnabled(true);
+                if (hasPdfViewer()) {
+                    mPrintPreviewButton.setText(getString(R.string.print_preview));
+                } else {
+                    mPrintPreviewButton.setText(getString(R.string.install_for_print_preview));
+                }
+
+                // Print
+                mPrintButton.setEnabled(true);
+            }
+
+            // Here is some voodoo to circumvent the weird behavior of AdapterView
+            // in which a selection listener may get a callback for an event that
+            // happened before the listener was registered. The reason for that is
+            // that the selection change is handled on the next layout pass.
+            Choreographer.getInstance().postCallback(Choreographer.CALLBACK_TRAVERSAL,
+                    new Runnable() {
+                @Override
+                public void run() {
+                    mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+                    mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+                    mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+                    mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+                }
+            }, null);
+        }
+
+        public PrinterInfo getCurrentPrinter() {
+            final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
+            if (selectedIndex >= 0) {
+                return mDestinationSpinnerAdapter.getItem(selectedIndex).value;
+            }
+            return null;
+        }
+
+        public void addPrinters(List<PrinterInfo> addedPrinters) {
+            final int addedPrinterCount = addedPrinters.size();
+            for (int i = 0; i < addedPrinterCount; i++) {
+                PrinterInfo addedPrinter = addedPrinters.get(i);
+                boolean duplicate = false;
+                final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
+                for (int j = 0; j < existingPrinterCount; j++) {
+                    PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
+                    if (addedPrinter.getId().equals(existingPrinter.getId())) {
+                        duplicate = true;
+                        break;
+                    }
+                }
+                if (!duplicate) {
+                    mDestinationSpinnerAdapter.add(new SpinnerItem<PrinterInfo>(
+                            addedPrinter, addedPrinter.getLabel()));
+                } else {
+                    Log.w(LOG_TAG, "Skipping a duplicate printer: " + addedPrinter);
+                }
+            }
+
+            if (mDestinationSpinner.getSelectedItemPosition() == AdapterView.INVALID_POSITION
+                    && mDestinationSpinnerAdapter.getCount() > 0) {
+                mDestinationSpinner.setSelection(0);
+            }
+        }
+
+        public void removePrinters(List<PrinterId> pritnerIds) {
+            final int printerIdCount = pritnerIds.size();
+            for (int i = 0; i < printerIdCount; i++) {
+                PrinterId removedPrinterId = pritnerIds.get(i);
+                boolean removed = false;
+                final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
+                for (int j = 0; j < existingPrinterCount; j++) {
+                    PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
+                    if (removedPrinterId.equals(existingPrinter.getId())) {
+                        mDestinationSpinnerAdapter.remove(mDestinationSpinnerAdapter.getItem(j));
+                        removed = true;
+                        break;
+                    }
+                }
+                if (!removed) {
+                    Log.w(LOG_TAG, "Ignoring not added printer with id: " + removedPrinterId);
+                }
+            }
+
+            if (mDestinationSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION
+                    && mDestinationSpinnerAdapter.getCount() == 0) {
+                mDestinationSpinner.setSelection(AdapterView.INVALID_POSITION);
+            }
+        }
+
+        private void updatePrintPreview(File file) {
+            // TODO: Implement
+        }
+    }
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
index 0546a43..53ae1459 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
@@ -24,10 +24,15 @@
 import android.print.IPrintClient;
 import android.print.IPrintSpoolerClient;
 import android.print.IPrinterDiscoveryObserver;
+import android.print.PageRange;
 import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintAttributes.Tray;
+import android.print.PrintDocumentInfo;
 import android.print.PrintJobInfo;
 import android.print.PrintManager;
-import android.print.PrintDocumentInfo;
 import android.print.PrinterId;
 import android.util.AtomicFile;
 import android.util.Log;
@@ -58,9 +63,9 @@
 
     private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
 
-    private static final boolean DEBUG_PERSISTENCE = false;
+    private static final boolean DEBUG_PERSISTENCE = true;
 
-    private static final boolean PERSISTNECE_MANAGER_ENABLED = false;
+    private static final boolean PERSISTNECE_MANAGER_ENABLED = true;
 
     private static final String PRINT_FILE_EXTENSION = "pdf";
 
@@ -91,8 +96,7 @@
 
     private PrintSpooler(Context context) {
         mContext = context;
-        mPersistanceManager = new PersistenceManager();
-        mPersistanceManager.readStateLocked();
+        mPersistanceManager = new PersistenceManager(context);
     }
 
     public void setCleint(IPrintSpoolerClient client) {
@@ -101,6 +105,12 @@
         }
     }
 
+    public void restorePersistedState() {
+        synchronized (mLock) {
+            mPersistanceManager.readStateLocked();
+        }
+    }
+
     public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) {
         IPrintSpoolerClient client = null;
         synchronized (mLock) {
@@ -129,7 +139,7 @@
         }
     }
 
-    public List<PrintJobInfo> getPrintJobs(ComponentName componentName, int state, int appId) {
+    public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state, int appId) {
         synchronized (mLock) {
             List<PrintJobInfo> foundPrintJobs = null;
             final int printJobCount = mPrintJobs.size();
@@ -141,8 +151,10 @@
                         && componentName.equals(printerId.getService())));
                 final boolean sameAppId = appId == PrintManager.APP_ID_ANY
                         || printJob.getAppId() == appId;
-                final boolean sameState = state == PrintJobInfo.STATE_ANY
-                        || state == printJob.getState();
+                final boolean sameState = (state == printJob.getState())
+                        || (state == PrintJobInfo.STATE_ANY)
+                        || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS
+                                && printJob.getState() > PrintJobInfo.STATE_CREATED);
                 if (sameComponent && sameAppId && sameState) {
                     if (foundPrintJobs == null) {
                         foundPrintJobs = new ArrayList<PrintJobInfo>();
@@ -154,7 +166,7 @@
         }
     }
 
-    public PrintJobInfo getPrintJob(int printJobId, int appId) {
+    public PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
         synchronized (mLock) {
             final int printJobCount = mPrintJobs.size();
             for (int i = 0; i < printJobCount; i++) {
@@ -170,7 +182,7 @@
 
     public boolean cancelPrintJob(int printJobId, int appId) {
         synchronized (mLock) {
-            PrintJobInfo printJob = getPrintJob(printJobId, appId);
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, appId);
             if (printJob != null) {
                 switch (printJob.getState()) {
                     case PrintJobInfo.STATE_CREATED:
@@ -192,9 +204,9 @@
             printJob.setAppId(appId);
             printJob.setLabel(label);
             printJob.setAttributes(attributes);
+            printJob.setState(PrintJobInfo.STATE_CREATED);
 
             addPrintJobLocked(printJob);
-            setPrintJobState(printJobId, PrintJobInfo.STATE_CREATED);
 
             return printJob;
         }
@@ -291,7 +303,7 @@
             FileInputStream in = null;
             FileOutputStream out = null;
             try {
-                PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
+                PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
                 if (printJob != null) {
                     File file = generateFileForPrintJob(printJobId);
                     in = new FileInputStream(file);
@@ -355,7 +367,7 @@
             }
             client = mClient;
 
-            PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
             if (printJob != null && printJob.getState() < state) {
                 success = true;
                 printJob.setState(state);
@@ -425,12 +437,22 @@
         }
     }
 
-    private void callOnAllPrintJobsHandledQuietly(IPrintSpoolerClient client) {
-        try {
-            client.onAllPrintJobsHandled();
-        } catch (RemoteException re) {
-            Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
-        }
+    private void callOnAllPrintJobsHandledQuietly(final IPrintSpoolerClient client) {
+        // This has to run on the tread that is persisting the current state
+        // since this call may result in the system unbinding from the spooler
+        // and as a result the spooler process may get killed before the write
+        // completes.
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                try {
+                    client.onAllPrintJobsHandled();
+                } catch (RemoteException re) {
+                    Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
+                }
+                return null;
+            }
+        }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
     }
 
     private boolean hasActivePrintJobsLocked() {
@@ -465,7 +487,7 @@
 
     public boolean setPrintJobTag(int printJobId, String tag) {
         synchronized (mLock) {
-            PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
             if (printJob != null) {
                 printJob.setTag(tag);
                 mPersistanceManager.writeStateLocked();
@@ -477,7 +499,7 @@
 
     public final boolean setPrintJobPrintDocumentInfo(int printJobId, PrintDocumentInfo info) {
         synchronized (mLock) {
-            PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
             if (printJob != null) {
                 printJob.setDocumentInfo(info);
                 mPersistanceManager.writeStateLocked();
@@ -489,7 +511,7 @@
 
     public void setPrintJobAttributes(int printJobId, PrintAttributes attributes) {
         synchronized (mLock) {
-            PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
             if (printJob != null) {
                 printJob.setAttributes(attributes);
                 mPersistanceManager.writeStateLocked();
@@ -499,7 +521,7 @@
 
     public void setPrintJobPrinterId(int printJobId, PrinterId printerId) {
         synchronized (mLock) {
-            PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
             if (printJob != null) {
                 printJob.setPrinterId(printerId);
                 mPersistanceManager.writeStateLocked();
@@ -507,40 +529,77 @@
         }
     }
 
+    public boolean setPrintJobPages(int printJobId, PageRange[] pages) {
+        synchronized (mLock) {
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
+            if (printJob != null) {
+                printJob.setPages(pages);
+                mPersistanceManager.writeStateLocked();
+                return true;
+            }
+        }
+        return false;
+    }
+
     private final class PersistenceManager {
         private static final String PERSIST_FILE_NAME = "print_spooler_state.xml";
 
         private static final String TAG_SPOOLER = "spooler";
         private static final String TAG_JOB = "job";
-        private static final String TAG_ID = "id";
-        private static final String TAG_TAG = "tag";
-        private static final String TAG_APP_ID = "app-id";
-        private static final String TAG_STATE = "state";
-        private static final String TAG_ATTRIBUTES = "attributes";
-        private static final String TAG_LABEL = "label";
-        private static final String TAG_PRINTER = "printer";
 
-        private static final String ATTRIBUTE_MEDIA_SIZE = "mediaSize";
-        private static final String ATTRIBUTE_RESOLUTION = "resolution";
-        private static final String ATTRIBUTE_MARGINS = "margins";
-        private static final String ATTRIBUTE_INPUT_TRAY = "inputTray";
-        private static final String ATTRIBUTE_OUTPUT_TRAY = "outputTray";
-        private static final String ATTRIBUTE_DUPLEX_MODE = "duplexMode";
-        private static final String ATTRIBUTE_COLOR_MODE = "colorMode";
-        private static final String ATTRIBUTE_FITTING_MODE = "fittingMode";
-        private static final String ATTRIBUTE_ORIENTATION = "orientation";
+        private static final String TAG_PRINTER_ID = "printerId";
+        private static final String TAG_PAGE_RANGE = "pageRange";
+        private static final String TAG_ATTRIBUTES = "attributes";
+        private static final String TAG_DOCUMENT_INFO = "documentInfo";
+
+        private static final String ATTR_ID = "id";
+        private static final String ATTR_LABEL = "label";
+        private static final String ATTR_STATE = "state";
+        private static final String ATTR_APP_ID = "appId";
+        private static final String ATTR_USER_ID = "userId";
+        private static final String ATTR_TAG = "tag";
+
+        private static final String TAG_MEDIA_SIZE = "mediaSize";
+        private static final String TAG_RESOLUTION = "resolution";
+        private static final String TAG_MARGINS = "margins";
+        private static final String TAG_INPUT_TRAY = "inputTray";
+        private static final String TAG_OUTPUT_TRAY = "outputTray";
+
+        private static final String ATTR_DUPLEX_MODE = "duplexMode";
+        private static final String ATTR_COLOR_MODE = "colorMode";
+        private static final String ATTR_FITTING_MODE = "fittingMode";
+        private static final String ATTR_ORIENTATION = "orientation";
+
+        private static final String ATTR_LOCAL_ID = "localId";
+        private static final String ATTR_SERVICE = "service";
+
+        private static final String ATTR_WIDTH_MILS = "widthMils";
+        private static final String ATTR_HEIGHT_MILS = "heightMils";
+
+        private static final String ATTR_HORIZONTAL_DPI = "horizontalDip";
+        private static final String ATTR_VERTICAL_DPI = "verticalDpi";
+
+        private static final String ATTR_LEFT_MILS = "leftMils";
+        private static final String ATTR_TOP_MILS = "topMils";
+        private static final String ATTR_RIGHT_MILS = "rightMils";
+        private static final String ATTR_BOTTOM_MILS = "bottomMils";
+
+        private static final String ATTR_START = "start";
+        private static final String ATTR_END = "end";
+
+        private static final String ATTR_PAGE_COUNT = "pageCount";
+        private static final String ATTR_CONTENT_TYPE = "contentType";
 
         private final AtomicFile mStatePersistFile;
 
         private boolean mWriteStateScheduled;
 
-        private PersistenceManager() {
-            mStatePersistFile = new AtomicFile(new File(mContext.getFilesDir(),
+        private PersistenceManager(Context context) {
+            mStatePersistFile = new AtomicFile(new File(context.getFilesDir(),
                     PERSIST_FILE_NAME));
         }
 
         public void writeStateLocked() {
-            // TODO: Implement persistence of PrintableInfo
             if (!PERSISTNECE_MANAGER_ENABLED) {
                 return;
             }
@@ -578,99 +637,134 @@
 
                     final int state = printJob.getState();
                     if (state < PrintJobInfo.STATE_QUEUED
-                            || state > PrintJobInfo.STATE_FAILED) {
+                            || state > PrintJobInfo.STATE_CANCELED) {
                         continue;
                     }
 
                     serializer.startTag(null, TAG_JOB);
 
-                    serializer.startTag(null, TAG_ID);
-                    serializer.text(String.valueOf(printJob.getId()));
-                    serializer.endTag(null, TAG_ID);
+                    serializer.attribute(null, ATTR_ID, String.valueOf(printJob.getId()));
+                    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()));
+                    serializer.attribute(null, ATTR_USER_ID, String.valueOf(printJob.getUserId()));
+                    String tag = printJob.getTag();
+                    if (tag != null) {
+                        serializer.attribute(null, ATTR_TAG, tag);
+                    }
 
-                    serializer.startTag(null, TAG_TAG);
-                    serializer.text(printJob.getTag());
-                    serializer.endTag(null, TAG_TAG);
+                    PrinterId printerId = printJob.getPrinterId();
+                    if (printerId != null) {
+                        serializer.startTag(null, TAG_PRINTER_ID);
+                        serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId());
+                        serializer.attribute(null, ATTR_SERVICE, printerId.getService()
+                                .flattenToString());
+                        serializer.endTag(null, TAG_PRINTER_ID);
+                    }
 
-                    serializer.startTag(null, TAG_APP_ID);
-                    serializer.text(String.valueOf(printJob.getAppId()));
-                    serializer.endTag(null, TAG_APP_ID);
-
-                    serializer.startTag(null, TAG_LABEL);
-                    serializer.text(printJob.getLabel().toString());
-                    serializer.endTag(null, TAG_LABEL);
-
-                    serializer.startTag(null, TAG_STATE);
-                    serializer.text(String.valueOf(printJob.getState()));
-                    serializer.endTag(null, TAG_STATE);
-
-                    serializer.startTag(null, TAG_PRINTER);
-                    serializer.text(printJob.getPrinterId().flattenToString());
-                    serializer.endTag(null, TAG_PRINTER);
+                    PageRange[] pages = printJob.getPages();
+                    if (pages != null) {
+                        for (int i = 0; i < pages.length; i++) {
+                            serializer.startTag(null, TAG_PAGE_RANGE);
+                            serializer.attribute(null, ATTR_START, String.valueOf(
+                                    pages[i].getStart()));
+                            serializer.attribute(null, ATTR_END, String.valueOf(
+                                    pages[i].getEnd()));
+                            serializer.endTag(null, TAG_PAGE_RANGE);
+                        }
+                    }
 
                     PrintAttributes attributes = printJob.getAttributes();
                     if (attributes != null) {
                         serializer.startTag(null, TAG_ATTRIBUTES);
 
-                            //TODO: Implement persistence of the attributes below.
-
-//                            MediaSize mediaSize = attributes.getMediaSize();
-//                            if (mediaSize != null) {
-//                                serializer.attribute(null, ATTRIBUTE_MEDIA_SIZE,
-//                                        mediaSize.flattenToString());
-//                            }
-//
-//                            Resolution resolution = attributes.getResolution();
-//                            if (resolution != null) {
-//                                serializer.attribute(null, ATTRIBUTE_RESOLUTION,
-//                                        resolution.flattenToString());
-//                            }
-//
-//                            Margins margins = attributes.getMargins();
-//                            if (margins != null) {
-//                                serializer.attribute(null, ATTRIBUTE_MARGINS,
-//                                        margins.flattenToString());
-//                            }
-//
-//                            Tray inputTray = attributes.getInputTray();
-//                            if (inputTray != null) {
-//                                serializer.attribute(null, ATTRIBUTE_INPUT_TRAY,
-//                                        inputTray.flattenToString());
-//                            }
-//
-//                            Tray outputTray = attributes.getOutputTray();
-//                            if (outputTray != null) {
-//                                serializer.attribute(null, ATTRIBUTE_OUTPUT_TRAY,
-//                                        outputTray.flattenToString());
-//                            }
-
                         final int duplexMode = attributes.getDuplexMode();
-                        if (duplexMode > 0) {
-                            serializer.attribute(null, ATTRIBUTE_DUPLEX_MODE,
-                                    String.valueOf(duplexMode));
-                        }
+                        serializer.attribute(null, ATTR_DUPLEX_MODE,
+                                String.valueOf(duplexMode));
 
                         final int colorMode = attributes.getColorMode();
-                        if (colorMode > 0) {
-                            serializer.attribute(null, ATTRIBUTE_COLOR_MODE,
-                                    String.valueOf(colorMode));
-                        }
+                        serializer.attribute(null, ATTR_COLOR_MODE,
+                                String.valueOf(colorMode));
 
                         final int fittingMode = attributes.getFittingMode();
-                        if (fittingMode > 0) {
-                            serializer.attribute(null, ATTRIBUTE_FITTING_MODE,
-                                    String.valueOf(fittingMode));
-                        }
+                        serializer.attribute(null, ATTR_FITTING_MODE,
+                                String.valueOf(fittingMode));
 
                         final int orientation = attributes.getOrientation();
-                        if (orientation > 0) {
-                            serializer.attribute(null, ATTRIBUTE_ORIENTATION,
-                                    String.valueOf(orientation));
+                        serializer.attribute(null, ATTR_ORIENTATION,
+                                String.valueOf(orientation));
+
+                        MediaSize mediaSize = attributes.getMediaSize();
+                        if (mediaSize != null) {
+                            serializer.startTag(null, TAG_MEDIA_SIZE);
+                            serializer.attribute(null, ATTR_ID, mediaSize.getId());
+                            serializer.attribute(null, ATTR_LABEL, mediaSize.getLabel()
+                                    .toString());
+                            serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf(
+                                    mediaSize.getWidthMils()));
+                            serializer.attribute(null, ATTR_HEIGHT_MILS,String.valueOf(
+                                    mediaSize.getHeightMils()));
+                            serializer.endTag(null, TAG_MEDIA_SIZE);
+                        }
+
+                        Resolution resolution = attributes.getResolution();
+                        if (resolution != null) {
+                            serializer.startTag(null, TAG_RESOLUTION);
+                            serializer.attribute(null, ATTR_ID, resolution.getId());
+                            serializer.attribute(null, ATTR_LABEL, resolution.getLabel()
+                                    .toString());
+                            serializer.attribute(null, ATTR_HORIZONTAL_DPI, String.valueOf(
+                                     resolution.getHorizontalDpi()));
+                            serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf(
+                                    resolution.getVerticalDpi()));
+                            serializer.endTag(null, TAG_RESOLUTION);
+                        }
+
+                        Margins margins = attributes.getMargins();
+                        if (margins != null) {
+                            serializer.startTag(null, TAG_MARGINS);
+                            serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf(
+                                    margins.getLeftMils()));
+                            serializer.attribute(null, ATTR_TOP_MILS, String.valueOf(
+                                    margins.getTopMils()));
+                            serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf(
+                                    margins.getRightMils()));
+                            serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf(
+                                    margins.getBottomMils()));
+                            serializer.endTag(null, TAG_MARGINS);
+                        }
+
+                        Tray inputTray = attributes.getInputTray();
+                        if (inputTray != null) {
+                            serializer.startTag(null, TAG_INPUT_TRAY);
+                            serializer.attribute(null, ATTR_ID, inputTray.getId());
+                            serializer.attribute(null, ATTR_LABEL, inputTray.getLabel()
+                                    .toString());
+                            serializer.endTag(null, TAG_INPUT_TRAY);
+                        }
+
+                        Tray outputTray = attributes.getOutputTray();
+                        if (outputTray != null) {
+                            serializer.startTag(null, TAG_OUTPUT_TRAY);
+                            serializer.attribute(null, ATTR_ID, outputTray.getId());
+                            serializer.attribute(null, ATTR_LABEL, outputTray.getLabel()
+                                    .toString());
+                            serializer.endTag(null, TAG_OUTPUT_TRAY);
                         }
 
                         serializer.endTag(null, TAG_ATTRIBUTES);
                     }
 
+                    PrintDocumentInfo documentInfo = printJob.getDocumentInfo();
+                    if (documentInfo != null) {
+                        serializer.startTag(null, TAG_DOCUMENT_INFO);
+                        serializer.attribute(null, ATTR_CONTENT_TYPE, String.valueOf(
+                                documentInfo.getContentType()));
+                        serializer.attribute(null, ATTR_PAGE_COUNT, String.valueOf(
+                                documentInfo.getPageCount()));
+                        serializer.endTag(null, TAG_DOCUMENT_INFO);
+                    }
+
                     serializer.endTag(null, TAG_JOB);
 
                     if (DEBUG_PERSISTENCE) {
@@ -752,125 +846,169 @@
             if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) {
                 return false;
             }
-            parser.next();
-
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.START_TAG, TAG_ID);
-            parser.next();
-            final int printJobId = Integer.parseInt(parser.getText());
-            parser.next();
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.END_TAG, TAG_ID);
-            parser.next();
-
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.START_TAG, TAG_TAG);
-            parser.next();
-            String tag = parser.getText();
-            parser.next();
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.END_TAG, TAG_TAG);
-            parser.next();
-
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.START_TAG, TAG_APP_ID);
-            parser.next();
-            final int appId = Integer.parseInt(parser.getText());
-            parser.next();
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.END_TAG, TAG_APP_ID);
-            parser.next();
-
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.START_TAG, TAG_LABEL);
-            parser.next();
-            String label = parser.getText();
-            parser.next();
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.END_TAG, TAG_LABEL);
-            parser.next();
-
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.START_TAG, TAG_STATE);
-            parser.next();
-            final int state = Integer.parseInt(parser.getText());
-            parser.next();
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.END_TAG, TAG_STATE);
-            parser.next();
-
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.START_TAG, TAG_PRINTER);
-            parser.next();
-            PrinterId printerId = PrinterId.unflattenFromString(parser.getText());
-            parser.next();
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.END_TAG, TAG_PRINTER);
-            parser.next();
-
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES);
-
-            final int attributeCount = parser.getAttributeCount();
-            PrintAttributes attributes = null;
-            if (attributeCount > 0) {
-                PrintAttributes.Builder builder = new PrintAttributes.Builder();
-
-                // TODO: Implement reading of the attributes below.
-
-//                String mediaSize = parser.getAttributeValue(null, ATTRIBUTE_MEDIA_SIZE);
-//                if (mediaSize != null) {
-//                    builder.setMediaSize(MediaSize.unflattenFromString(mediaSize));
-//                }
-//
-//                String resolution = parser.getAttributeValue(null, ATTRIBUTE_RESOLUTION);
-//                if (resolution != null) {
-//                    builder.setMediaSize(Resolution.unflattenFromString(resolution));
-//                }
-//
-//                String margins = parser.getAttributeValue(null, ATTRIBUTE_MARGINS);
-//                if (margins != null) {
-//                    builder.setMediaSize(Margins.unflattenFromString(margins));
-//                }
-//
-//                String inputTray = parser.getAttributeValue(null, ATTRIBUTE_INPUT_TRAY);
-//                if (inputTray != null) {
-//                    builder.setMediaSize(Tray.unflattenFromString(inputTray));
-//                }
-//
-//                String outputTray = parser.getAttributeValue(null, ATTRIBUTE_OUTPUT_TRAY);
-//                if (outputTray != null) {
-//                    builder.setMediaSize(Tray.unflattenFromString(outputTray));
-//                }
-//
-//                String duplexMode = parser.getAttributeValue(null, ATTRIBUTE_DUPLEX_MODE);
-//                if (duplexMode != null) {
-//                    builder.setDuplexMode(Integer.parseInt(duplexMode));
-//                }
-
-                String colorMode = parser.getAttributeValue(null, ATTRIBUTE_COLOR_MODE);
-                if (colorMode != null) {
-                    builder.setColorMode(Integer.parseInt(colorMode));
-                }
-
-                String fittingMode = parser.getAttributeValue(null, ATTRIBUTE_COLOR_MODE);
-                if (fittingMode != null) {
-                    builder.setFittingMode(Integer.parseInt(fittingMode));
-                }
-            }
-            parser.next();
-            skipEmptyTextTags(parser);
-            expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES);
-            parser.next();
 
             PrintJobInfo printJob = new PrintJobInfo();
+
+            final int printJobId = Integer.parseInt(parser.getAttributeValue(null, ATTR_ID));
             printJob.setId(printJobId);
-            printJob.setTag(tag);
-            printJob.setAppId(appId);
+            String label = parser.getAttributeValue(null, ATTR_LABEL);
             printJob.setLabel(label);
+            final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE));
             printJob.setState(state);
-            printJob.setAttributes(attributes);
-            printJob.setPrinterId(printerId);
+            final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID));
+            printJob.setAppId(appId);
+            final int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USER_ID));
+            printJob.setUserId(userId);
+            String tag = parser.getAttributeValue(null, ATTR_TAG);
+            printJob.setTag(tag);
+
+            parser.next();
+
+            skipEmptyTextTags(parser);
+            if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) {
+                String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID);
+                ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue(
+                        null, ATTR_SERVICE));
+                printJob.setPrinterId(new PrinterId(service, localId));
+                parser.next();
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
+                parser.next();
+            }
+
+            skipEmptyTextTags(parser);
+            List<PageRange> pageRanges = null;
+            while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) {
+                final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START));
+                final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END));
+                PageRange pageRange = new PageRange(start, end);
+                if (pageRanges == null) {
+                    pageRanges = new ArrayList<PageRange>();
+                }
+                pageRanges.add(pageRange);
+                parser.next();
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE);
+                parser.next();
+            }
+            if (pageRanges != null) {
+                printJob.setPages((PageRange[]) pageRanges.toArray());
+            }
+
+            skipEmptyTextTags(parser);
+            if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) {
+
+                PrintAttributes.Builder builder = new PrintAttributes.Builder();
+
+                String duplexMode = parser.getAttributeValue(null, ATTR_DUPLEX_MODE);
+                builder.setDuplexMode(Integer.parseInt(duplexMode));
+
+                String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE);
+                builder.setColorMode(Integer.parseInt(colorMode));
+
+                String fittingMode = parser.getAttributeValue(null, ATTR_FITTING_MODE);
+                builder.setFittingMode(Integer.parseInt(fittingMode));
+
+                String orientation = parser.getAttributeValue(null, ATTR_ORIENTATION);
+                builder.setOrientation(Integer.parseInt(orientation));
+
+                parser.next();
+
+                skipEmptyTextTags(parser);
+                if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) {
+                    String id = parser.getAttributeValue(null, ATTR_ID);
+                    label = parser.getAttributeValue(null, ATTR_LABEL);
+                    final int widthMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_WIDTH_MILS));
+                    final int heightMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_HEIGHT_MILS));
+                    MediaSize mediaSize = new MediaSize(id, label, widthMils, heightMils);
+                    builder.setMediaSize(mediaSize);
+                    parser.next();
+                    skipEmptyTextTags(parser);
+                    expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE);
+                    parser.next();
+                }
+
+                skipEmptyTextTags(parser);
+                if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) {
+                    String id = parser.getAttributeValue(null, ATTR_ID);
+                    label = parser.getAttributeValue(null, ATTR_LABEL);
+                    final int horizontalDpi = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_HORIZONTAL_DPI));
+                    final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_VERTICAL_DPI));
+                    Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi);
+                    builder.setResolution(resolution);
+                    parser.next();
+                    skipEmptyTextTags(parser);
+                    expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION);
+                    parser.next();
+                }
+
+                skipEmptyTextTags(parser);
+                if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) {
+                    final int leftMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_LEFT_MILS));
+                    final int topMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_TOP_MILS));
+                    final int rightMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_RIGHT_MILS));
+                    final int bottomMils = Integer.parseInt(parser.getAttributeValue(null,
+                            ATTR_BOTTOM_MILS));
+                    Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils);
+                    builder.setMargins(margins);
+                    parser.next();
+                    skipEmptyTextTags(parser);
+                    expect(parser, XmlPullParser.END_TAG, TAG_MARGINS);
+                    parser.next();
+                }
+
+                skipEmptyTextTags(parser);
+                if (accept(parser, XmlPullParser.START_TAG, TAG_INPUT_TRAY)) {
+                    String id = parser.getAttributeValue(null, ATTR_ID);
+                    label = parser.getAttributeValue(null, ATTR_LABEL);
+                    Tray tray = new Tray(id, label);
+                    builder.setInputTray(tray);
+                    parser.next();
+                    skipEmptyTextTags(parser);
+                    expect(parser, XmlPullParser.END_TAG, TAG_INPUT_TRAY);
+                    parser.next();
+                }
+
+                skipEmptyTextTags(parser);
+                if (accept(parser, XmlPullParser.START_TAG, TAG_OUTPUT_TRAY)) {
+                    String id = parser.getAttributeValue(null, ATTR_ID);
+                    label = parser.getAttributeValue(null, ATTR_LABEL);
+                    Tray tray = new Tray(id, label);
+                    builder.setOutputTray(tray);
+                    parser.next();
+                    skipEmptyTextTags(parser);
+                    expect(parser, XmlPullParser.END_TAG, TAG_OUTPUT_TRAY);
+                    parser.next();
+                }
+
+                printJob.setAttributes(builder.create());
+
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES);
+                parser.next();
+            }
+
+            skipEmptyTextTags(parser);
+            if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) {
+                final int pageCount = Integer.parseInt(parser.getAttributeValue(null,
+                        ATTR_PAGE_COUNT));
+                final int contentType = Integer.parseInt(parser.getAttributeValue(null,
+                        ATTR_CONTENT_TYPE));
+                PrintDocumentInfo info = new PrintDocumentInfo.Builder().setPageCount(pageCount)
+                        .setContentType(contentType).create();
+                printJob.setDocumentInfo(info);
+                parser.next();
+                skipEmptyTextTags(parser);
+                expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO);
+                parser.next();
+            }
 
             mPrintJobs.add(printJob);
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 050332c..26d2a33 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -65,6 +65,8 @@
 
     @Override
     public IBinder onBind(Intent intent) {
+        mSpooler.restorePersistedState();
+
         return new IPrintSpooler.Stub() {
             @Override
             public void getPrintJobInfos(IPrintSpoolerCallbacks callback,
@@ -72,7 +74,7 @@
                             throws RemoteException {
                 List<PrintJobInfo> printJobs = null;
                 try {
-                    printJobs = mSpooler.getPrintJobs(componentName, state, appId);
+                    printJobs = mSpooler.getPrintJobInfos(componentName, state, appId);
                 } finally {
                     callback.onGetPrintJobInfosResult(printJobs, sequence);
                 }
@@ -83,7 +85,7 @@
                     int appId, int sequence) throws RemoteException {
                 PrintJobInfo printJob = null;
                 try {
-                    printJob = mSpooler.getPrintJob(printJobId, appId);
+                    printJob = mSpooler.getPrintJobInfo(printJobId, appId);
                 } finally {
                     callback.onGetPrintJobInfoResult(printJob, sequence);
                 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
index 7186932..25bb37c 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
@@ -32,6 +32,8 @@
 import android.util.Log;
 import android.util.Slog;
 
+import libcore.io.IoUtils;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -41,8 +43,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import libcore.io.IoUtils;
-
 /**
  * This class represents a remote print document adapter instance.
  */
@@ -53,9 +53,12 @@
 
     public static final int STATE_INITIALIZED = 0;
     public static final int STATE_START_COMPLETED = 1;
-    public static final int STATE_LAYOUT_COMPLETED = 2;
-    public static final int STATE_WRITE_COMPLETED = 3;
-    public static final int STATE_FINISH_COMPLETED = 4;
+    public static final int STATE_LAYOUT_STARTED = 2;
+    public static final int STATE_LAYOUT_COMPLETED = 3;
+    public static final int STATE_WRITE_STARTED = 4;
+    public static final int STATE_WRITE_COMPLETED = 5;
+    public static final int STATE_FINISH_COMPLETED = 6;
+    public static final int STATE_FAILED = 7;
 
     private final Object mLock = new Object();
 
@@ -77,22 +80,14 @@
             Log.i(LOG_TAG, "getFile()");
         }
         synchronized (mLock) {
-            if (mState < STATE_WRITE_COMPLETED) {
+            if (mState != STATE_WRITE_COMPLETED
+                    && mState != STATE_FINISH_COMPLETED) {
                 throw new IllegalStateException("Write not completed");
             }
             return mFile;
         }
     }
 
-    public void cancel() {
-        synchronized (mLock) {
-            final int taskCount = mTaskQueue.size();
-            for (int i = 0; i < taskCount; i++) {
-                mTaskQueue.remove(i).cancel();
-            }
-        }
-    }
-
     public void start() {
         QueuedAsyncTask task = new QueuedAsyncTask() {
             @Override
@@ -115,11 +110,16 @@
                 }
                 return null;
             }
+
+            @Override
+            public void cancel() {
+                /* cannot be cancelled */
+            }
         };
         synchronized (mLock) {
             mTaskQueue.add(task);
-            task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
         }
+        task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
     }
 
     public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
@@ -128,27 +128,37 @@
                 metadata);
         synchronized (mLock) {
             mTaskQueue.add(task);
-            task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
         }
+        task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
     }
 
     public void write(List<PageRange> pages, WriteResultCallback callback) {
         WriteAsyncTask task = new WriteAsyncTask(pages, callback);
-        mTaskQueue.add(task);
+        synchronized (mLock) {
+            mTaskQueue.add(task);
+        }
         task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
     }
 
+    public void cancel() {
+        synchronized (mLock) {
+            final int taskCount = mTaskQueue.size();
+            for (int i = taskCount - 1; i >= 0; i--) {
+                mTaskQueue.remove(i).cancel();
+            }
+        }
+    }
+
     public void finish() {
         QueuedAsyncTask task = new QueuedAsyncTask() {
             @Override
             protected Void doInBackground(Void... params) {
                 if (DEBUG) {
-                    Log.i(LOG_TAG, "finish");
+                    Log.i(LOG_TAG, "finish()");
                 }
                 synchronized (mLock) {
-                    if (mState != STATE_LAYOUT_COMPLETED
-                            && mState != STATE_WRITE_COMPLETED) {
-                        throw new IllegalStateException("Invalid state: " + mState);
+                    if (mState < STATE_START_COMPLETED) {
+                        return null;
                     }
                 }
                 try {
@@ -158,15 +168,20 @@
                     }
                 } catch (RemoteException re) {
                     Log.e(LOG_TAG, "Error reading file", re);
-                    mState = STATE_INITIALIZED;
+                    mState = STATE_FAILED;
                 }
                 return null;
             }
+
+            @Override
+            public void cancel() {
+                /* cannot be cancelled */
+            }
         };
         synchronized (mLock) {
             mTaskQueue.add(task);
-            task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
         }
+        task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
     }
 
     private abstract class QueuedAsyncTask extends AsyncTask<Void, Void, Void> {
@@ -189,6 +204,9 @@
                 new ILayoutResultCallback.Stub() {
             @Override
             public void onLayoutStarted(ICancellationSignal cancellationSignal) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "onLayoutStarted()");
+                }
                 synchronized (mLock) {
                     mCancellationSignal = cancellationSignal;
                     if (isCancelled()) {
@@ -199,30 +217,43 @@
 
             @Override
             public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "onLayoutFinished()");
+                }
+                final boolean cancelled;
                 synchronized (mLock) {
+                    cancelled = isCancelled();
                     mCancellationSignal = null;
-                    mCompleted = true;
+                    mState = STATE_LAYOUT_COMPLETED;
+                    mTaskQueue.remove(this);
                     mLock.notifyAll();
                 }
-                mCallback.onLayoutFinished(info, changed);
+                if (!cancelled) {
+                    mCallback.onLayoutFinished(info, changed);
+                }
             }
 
             @Override
             public void onLayoutFailed(CharSequence error) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "onLayoutFailed()");
+                }
+                final boolean cancelled;
                 synchronized (mLock) {
+                    cancelled = isCancelled();
                     mCancellationSignal = null;
-                    mCompleted = true;
+                    mState = STATE_LAYOUT_COMPLETED;
+                    mTaskQueue.remove(this);
                     mLock.notifyAll();
                 }
-                Slog.e(LOG_TAG, "Error laying out print document: " + error);
-                mCallback.onLayoutFailed(error);
+                if (!cancelled) {
+                    mCallback.onLayoutFailed(error);
+                }
             }
         };
 
         private ICancellationSignal mCancellationSignal;
 
-        private boolean mCompleted;
-
         public LayoutAsyncTask(PrintAttributes oldAttributes, PrintAttributes newAttributes,
                 LayoutResultCallback callback, Bundle metadata) {
             mOldAttributes = oldAttributes;
@@ -243,25 +274,22 @@
         @Override
         protected Void doInBackground(Void... params) {
             synchronized (mLock) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "layout()");
+                }
                 if (mState != STATE_START_COMPLETED
                         && mState != STATE_LAYOUT_COMPLETED
                         && mState != STATE_WRITE_COMPLETED) {
                     throw new IllegalStateException("Invalid state: " + mState);
                 }
+                mState = STATE_LAYOUT_STARTED;
             }
             try {
                 mRemoteInterface.layout(mOldAttributes, mNewAttributes,
                         mILayoutResultCallback, mMetadata);
                 synchronized (mLock) {
                     while (true) {
-                        if (isCancelled()) {
-                            mState = STATE_INITIALIZED;
-                            mTaskQueue.remove(this);
-                            break;
-                        }
-                        if (mCompleted) {
-                            mState = STATE_LAYOUT_COMPLETED;
-                            mTaskQueue.remove(this);
+                        if (mState == STATE_LAYOUT_COMPLETED) {
                             break;
                         }
                         try {
@@ -273,7 +301,9 @@
                 }
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error calling layout", re);
-                mState = STATE_INITIALIZED;
+                mState = STATE_FAILED;
+                mTaskQueue.remove(this);
+                notifyLayoutFailedQuietly();
             }
             return null;
         }
@@ -284,10 +314,19 @@
                     mCancellationSignal.cancel();
                 } catch (RemoteException re) {
                     Slog.e(LOG_TAG, "Error cancelling layout", re);
+                    notifyLayoutFailedQuietly();
                 }
             }
         }
 
+        public void notifyLayoutFailedQuietly() {
+            try {
+                mILayoutResultCallback.onLayoutFailed(null);
+            } catch (RemoteException re) {
+                /* ignore */
+            }
+        }
+
         private void throwIfCancelledLocked() {
             if (isCancelled()) {
                 throw new IllegalStateException("Already cancelled");
@@ -305,6 +344,9 @@
                 new IWriteResultCallback.Stub() {
             @Override
             public void onWriteStarted(ICancellationSignal cancellationSignal) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "onWriteStarted()");
+                }
                 synchronized (mLock) {
                     mCancellationSignal = cancellationSignal;
                     if (isCancelled()) {
@@ -315,9 +357,13 @@
 
             @Override
             public void onWriteFinished(List<PageRange> pages) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "onWriteFinished()");
+                }
                 synchronized (mLock) {
                     mCancellationSignal = null;
-                    mCompleted = true;
+                    mState = STATE_WRITE_COMPLETED;
+                    mTaskQueue.remove(this);
                     mLock.notifyAll();
                 }
                 mCallback.onWriteFinished(pages);
@@ -325,9 +371,13 @@
 
             @Override
             public void onWriteFailed(CharSequence error) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "onWriteFailed()");
+                }
                 synchronized (mLock) {
                     mCancellationSignal = null;
-                    mCompleted = true;
+                    mState = STATE_WRITE_COMPLETED;
+                    mTaskQueue.remove(this);
                     mLock.notifyAll();
                 }
                 Slog.e(LOG_TAG, "Error writing print document: " + error);
@@ -337,8 +387,6 @@
 
         private ICancellationSignal mCancellationSignal;
 
-        private boolean mCompleted;
-
         private Thread mWriteThread;
 
         public WriteAsyncTask(List<PageRange> pages, WriteResultCallback callback) {
@@ -359,12 +407,14 @@
         @Override
         protected Void doInBackground(Void... params) {
             if (DEBUG) {
-                Log.i(LOG_TAG, "print()");
+                Log.i(LOG_TAG, "write()");
             }
             synchronized (mLock) {
-                if (mState != STATE_LAYOUT_COMPLETED) {
+                if (mState != STATE_LAYOUT_COMPLETED
+                        && mState != STATE_WRITE_COMPLETED) {
                     throw new IllegalStateException("Invalid state: " + mState);
                 }
+                mState = STATE_WRITE_STARTED;
             }
             InputStream in = null;
             OutputStream out = null;
@@ -402,14 +452,7 @@
                 }
                 synchronized (mLock) {
                     while (true) {
-                        if (isCancelled()) {
-                            mState = STATE_INITIALIZED;
-                            mTaskQueue.remove(this);
-                            break;
-                        }
-                        if (mCompleted) {
-                            mState = STATE_WRITE_COMPLETED;
-                            mTaskQueue.remove(this);
+                        if (mState == STATE_WRITE_COMPLETED) {
                             break;
                         }
                         try {
@@ -421,10 +464,14 @@
                 }
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error writing print document", re);
-                mState = STATE_INITIALIZED;
+                mState = STATE_FAILED;
+                mTaskQueue.remove(this);
+                notifyWriteFailedQuietly();
             } catch (IOException ioe) {
                 Slog.e(LOG_TAG, "Error writing print document", ioe);
-                mState = STATE_INITIALIZED;
+                mState = STATE_FAILED;
+                mTaskQueue.remove(this);
+                notifyWriteFailedQuietly();
             } finally {
                 IoUtils.closeQuietly(in);
                 IoUtils.closeQuietly(out);
@@ -440,10 +487,19 @@
                     mCancellationSignal.cancel();
                 } catch (RemoteException re) {
                     Slog.e(LOG_TAG, "Error cancelling layout", re);
+                    notifyWriteFailedQuietly();
                 }
             }
         }
 
+        private void notifyWriteFailedQuietly() {
+            try {
+                mIWriteResultCallback.onWriteFailed(null);
+            } catch (RemoteException re) {
+                /* ignore */
+            }
+        }
+
         private void throwIfCancelledLocked() {
             if (isCancelled()) {
                 throw new IllegalStateException("Already cancelled");
diff --git a/packages/SystemUI/res/anim/heads_up_enter.xml b/packages/SystemUI/res/anim/heads_up_enter.xml
index 4fd6a7c..59eef42 100644
--- a/packages/SystemUI/res/anim/heads_up_enter.xml
+++ b/packages/SystemUI/res/anim/heads_up_enter.xml
@@ -1,11 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         >
-    <scale
+    <translate
         android:interpolator="@android:interpolator/overshoot"
-        android:fromXScale="0.7" android:toXScale="1.0"
-        android:fromYScale="0.7" android:toYScale="1.0"
-        android:pivotX="50%" android:pivotY="50%"
+        android:fromYDelta="-50%" android:toYDelta="0"
         android:duration="@android:integer/config_shortAnimTime" />
     <alpha 
         android:interpolator="@android:interpolator/decelerate_quad"
diff --git a/packages/SystemUI/res/drawable/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable/heads_up_window_bg.9.png
index caad169..c68ccdc 100644
--- a/packages/SystemUI/res/drawable/heads_up_window_bg.9.png
+++ b/packages/SystemUI/res/drawable/heads_up_window_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index b7c1666..95eec0f 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -24,6 +24,7 @@
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:orientation="vertical"
+    android:paddingTop="@*android:dimen/status_bar_height"
     >
     <FrameLayout
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 7a5ff3c..f827967 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,4 +1,5 @@
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.ExpandableNotificationRow
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     >
@@ -62,4 +63,4 @@
         android:padding="2dp"
         />
 
-</FrameLayout>
+</com.android.systemui.statusbar.ExpandableNotificationRow>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index b70dee1..8ce959f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -101,5 +101,11 @@
 
     <!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
     <bool name="config_show4GForLTE">true</bool>
+
+    <!-- milliseconds before the heads up notification auto-dismisses. -->
+    <integer name="heads_up_notification_decay">3700</integer>
+
+    <!-- milliseconds before the heads up notification accepts touches. -->
+    <integer name="heads_up_sensitivity_delay">700</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 2cc3446..d876a95 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -16,8 +16,5 @@
 -->
 
 <resources>
-    <item type="id" name="expandable_tag" />
-    <item type="id" name="user_expanded_tag" />
-    <item type="id" name="user_lock_tag" />
     <item type="id" name="status_bar_cling_stub" />
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 4fd8aee..e1a4bb2 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -38,8 +38,8 @@
         View getChildAtRawPosition(float x, float y);
         View getChildAtPosition(float x, float y);
         boolean canChildBeExpanded(View v);
-        boolean setUserExpandedChild(View v, boolean userExpanded);
-        boolean setUserLockedChild(View v, boolean userLocked);
+        void setUserExpandedChild(View v, boolean userExpanded);
+        void setUserLockedChild(View v, boolean userLocked);
     }
 
     private static final String TAG = "ExpandHelper";
@@ -181,7 +181,6 @@
      * @param callback the container that holds the items to be manipulated
      * @param small the smallest allowable size for the manuipulated items.
      * @param large the largest allowable size for the manuipulated items.
-     * @param scoller if non-null also manipulate the scroll position to obey the gravity.
      */
     public ExpandHelper(Context context, Callback callback, int small, int large) {
         mSmallSize = small;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index b1e38d8..7025240 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.KeyguardManager;
+import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.TaskStackBuilder;
 import android.content.BroadcastReceiver;
@@ -91,7 +92,7 @@
 
     protected static final boolean ENABLE_HEADS_UP = true;
     // scores above this threshold should be displayed in heads up mode.
-    private static final int INTERRUPTION_THRESHOLD = 10;
+    private static final int INTERRUPTION_THRESHOLD = 11;
 
     // Should match the value in PhoneWindowManager
     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
@@ -108,7 +109,8 @@
     protected NotificationData mNotificationData = new NotificationData();
     protected NotificationRowLayout mPile;
 
-    protected StatusBarNotification mCurrentlyInterruptingNotification;
+    protected NotificationData.Entry mInterruptingNotificationEntry;
+    protected long mInterruptingNotificationTime;
 
     // used to notify status bar for suppressing notification LED
     protected boolean mPanelSlightlyVisible;
@@ -127,6 +129,7 @@
     protected IDreamManager mDreamManager;
     KeyguardManager mKeyguardManager;
     PowerManager mPowerManager;
+    protected int mRowHeight;
 
     // UI-specific methods
 
@@ -432,7 +435,7 @@
         }
     }
 
-    public void dismissHeadsUp() {
+    public void onHeadsUpDismissed() {
         // pass
     }
 
@@ -558,6 +561,8 @@
         }
     }
 
+    public abstract void resetHeadsUpDecayTimer();
+
     protected class H extends Handler {
         public void handleMessage(Message m) {
             Intent intent;
@@ -615,7 +620,7 @@
     protected void workAroundBadLayerDrawableOpacity(View v) {
     }
 
-    protected  boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
+    public boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
         int minHeight =
                 mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight =
@@ -630,7 +635,8 @@
         // create the row view
         LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
+        ExpandableNotificationRow row = (ExpandableNotificationRow) inflater.inflate(
+                R.layout.status_bar_notification_row, parent, false);
 
         // for blaming (see SwipeHelper.setLongPressListener)
         row.setTag(sbn.getPackageName());
@@ -697,6 +703,7 @@
             }
         }
         entry.row = row;
+        entry.row.setRowHeight(mRowHeight);
         entry.content = content;
         entry.expanded = contentViewLocal;
         entry.setBigContentView(bigContentViewLocal);
@@ -851,33 +858,18 @@
         return iconView;
     }
 
-    protected boolean expandView(NotificationData.Entry entry, boolean expand) {
-        int rowHeight =
-                mContext.getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
-        ViewGroup.LayoutParams lp = entry.row.getLayoutParams();
-        if (entry.expandable() && expand) {
-            if (DEBUG) Log.d(TAG, "setting expanded row height to WRAP_CONTENT");
-            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-        } else {
-            if (DEBUG) Log.d(TAG, "setting collapsed row height to " + rowHeight);
-            lp.height = rowHeight;
-        }
-        entry.row.setLayoutParams(lp);
-        return expand;
-    }
-
     protected void updateExpansionStates() {
         int N = mNotificationData.size();
         for (int i = 0; i < N; i++) {
             NotificationData.Entry entry = mNotificationData.get(i);
-            if (!entry.userLocked()) {
+            if (!entry.row.isUserLocked()) {
                 if (i == (N-1)) {
                     if (DEBUG) Log.d(TAG, "expanding top notification at " + i);
-                    expandView(entry, true);
+                    entry.row.setExpanded(true);
                 } else {
-                    if (!entry.userExpanded()) {
+                    if (!entry.row.isUserExpanded()) {
                         if (DEBUG) Log.d(TAG, "collapsing notification at " + i);
-                        expandView(entry, false);
+                        entry.row.setExpanded(false);
                     } else {
                         if (DEBUG) Log.d(TAG, "ignoring user-modified notification at " + i);
                     }
@@ -997,13 +989,13 @@
             if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
             if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
             if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
-            final boolean wasExpanded = oldEntry.userExpanded();
+            final boolean wasExpanded = oldEntry.row.isUserExpanded();
             removeNotificationViews(key);
             addNotificationViews(key, notification);
             if (wasExpanded) {
                 final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
-                expandView(newEntry, true);
-                newEntry.setUserExpanded(true);
+                newEntry.row.setExpanded(true);
+                newEntry.row.setUserExpanded(true);
             }
         }
 
@@ -1026,7 +1018,8 @@
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
 
         // See if we need to update the heads up.
-        if (ENABLE_HEADS_UP && oldNotification == mCurrentlyInterruptingNotification) {
+        if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
+                && oldNotification == mInterruptingNotificationEntry.notification) {
             if (DEBUG) Log.d(TAG, "updating the current heads up:" + notification);
             // XXX: this is a hack for Alarms. The real implementation will need to *update*
             // the heads up.
@@ -1037,15 +1030,28 @@
         }
     }
 
-    protected boolean shouldInterrupt(StatusBarNotification notification) {
-        boolean interrupt = notification.getNotification().fullScreenIntent == null
-                && notification.getScore() >= INTERRUPTION_THRESHOLD
-                && mPowerManager.isScreenOn() && !mKeyguardManager.isKeyguardLocked();
+    protected boolean shouldInterrupt(StatusBarNotification sbn) {
+        Notification notification = sbn.getNotification();
+        // some predicates to make the boolean logic legible
+        boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0
+                || (notification.defaults & Notification.DEFAULT_VIBRATE) != 0
+                || notification.sound != null
+                || notification.vibrate != null;
+        boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD;
+        boolean isFullscreen = notification.fullScreenIntent != null;
+        boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP,
+                Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER;
+
+        boolean interrupt = (isFullscreen || (isHighPriority && isNoisy))
+                && isAllowed
+                && mPowerManager.isScreenOn()
+                && !mKeyguardManager.isKeyguardLocked();
         try {
             interrupt = interrupt && !mDreamManager.isDreaming();
         } catch (RemoteException e) {
             Log.d(TAG, "failed to query dream manager", e);
         }
+        if (DEBUG) Log.d(TAG, "interrupt: " + interrupt);
         return interrupt;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
new file mode 100644
index 0000000..cd6495f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+public class ExpandableNotificationRow extends FrameLayout {
+    private int mRowHeight;
+
+    /** does this row contain layouts that can adapt to row expansion */
+    private boolean mExpandable;
+    /** has the user manually expanded this row */
+    private boolean mUserExpanded;
+    /** is the user touching this row */
+    private boolean mUserLocked;
+
+    public ExpandableNotificationRow(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public int getRowHeight() {
+        return mRowHeight;
+    }
+
+    public void setRowHeight(int rowHeight) {
+        this.mRowHeight = rowHeight;
+    }
+
+    public boolean isExpandable() {
+        return mExpandable;
+    }
+
+    public void setExpandable(boolean expandable) {
+        mExpandable = expandable;
+    }
+
+    public boolean isUserExpanded() {
+        return mUserExpanded;
+    }
+
+    public void setUserExpanded(boolean userExpanded) {
+        mUserExpanded = userExpanded;
+    }
+
+    public boolean isUserLocked() {
+        return mUserLocked;
+    }
+
+    public void setUserLocked(boolean userLocked) {
+        mUserLocked = userLocked;
+    }
+
+    public void setExpanded(boolean expand) {
+        ViewGroup.LayoutParams lp = getLayoutParams();
+        if (expand && mExpandable) {
+            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        } else {
+            lp.height = mRowHeight;
+        }
+        setLayoutParams(lp);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 8f62ebf..23950fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -34,7 +34,7 @@
         public IBinder key;
         public StatusBarNotification notification;
         public StatusBarIconView icon;
-        public View row; // the outer expanded view
+        public ExpandableNotificationRow row; // the outer expanded view
         public View content; // takes the click events and sends the PendingIntent
         public View expanded; // the inflated RemoteViews
         public ImageView largeIcon;
@@ -47,40 +47,16 @@
         }
         public void setBigContentView(View bigContentView) {
             this.expandedBig = bigContentView;
-            writeBooleanTag(row, R.id.expandable_tag, bigContentView != null);
+            row.setExpandable(bigContentView != null);
         }
         public View getBigContentView() {
             return expandedBig;
         }
         /**
-         * Return whether the entry can be expanded.
-         */
-        public boolean expandable() {
-            return NotificationData.getIsExpandable(row);
-        }
-        /**
-         * Return whether the entry has been manually expanded by the user.
-         */
-        public boolean userExpanded() {
-            return NotificationData.getUserExpanded(row);
-        }
-        /**
-         * Set the flag indicating that this was manually expanded by the user.
-         */
-        public boolean setUserExpanded(boolean userExpanded) {
-            return NotificationData.setUserExpanded(row, userExpanded);
-        }
-        /**
-         * Return whether the entry is being touched by the user.
-         */
-        public boolean userLocked() {
-            return NotificationData.getUserLocked(row);
-        }
-        /**
          * Set the flag indicating that this is being touched by the user.
          */
-        public boolean setUserLocked(boolean userLocked) {
-            return NotificationData.setUserLocked(row, userLocked);
+        public void setUserLocked(boolean userLocked) {
+            row.setUserLocked(userLocked);
         }
     }
     private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
@@ -125,8 +101,8 @@
         return i;
     }
 
-    public int add(IBinder key, StatusBarNotification notification, View row, View content,
-            View expanded, StatusBarIconView icon) {
+    public int add(IBinder key, StatusBarNotification notification, ExpandableNotificationRow row,
+            View content, View expanded, StatusBarIconView icon) {
         Entry entry = new Entry();
         entry.key = key;
         entry.notification = notification;
@@ -171,55 +147,4 @@
         }
         return false;
     }
-
-    protected static boolean readBooleanTag(View view, int id)  {
-        if (view != null) {
-            Object value = view.getTag(id);
-            return value != null && value instanceof Boolean && ((Boolean) value).booleanValue();
-        }
-        return false;
-    }
-
-    protected static boolean writeBooleanTag(View view, int id, boolean value)  {
-        if (view != null) {
-            view.setTag(id, Boolean.valueOf(value));
-            return value;
-        }
-        return false;
-    }
-
-    /**
-     * Return whether the entry can be expanded.
-     */
-    public static boolean getIsExpandable(View row) {
-        return readBooleanTag(row, R.id.expandable_tag);
-    }
-
-    /**
-     * Return whether the entry has been manually expanded by the user.
-     */
-    public static boolean getUserExpanded(View row) {
-        return readBooleanTag(row, R.id.user_expanded_tag);
-    }
-
-    /**
-     * Set whether the entry has been manually expanded by the user.
-     */
-    public static boolean setUserExpanded(View row, boolean userExpanded) {
-        return writeBooleanTag(row, R.id.user_expanded_tag, userExpanded);
-    }
-
-    /**
-     * Return whether the entry is being touched by the user.
-     */
-    public static boolean getUserLocked(View row) {
-        return readBooleanTag(row, R.id.user_lock_tag);
-    }
-
-    /**
-     * Set whether the entry is being touched by the user.
-     */
-    public static boolean setUserLocked(View row, boolean userLocked) {
-        return writeBooleanTag(row, R.id.user_lock_tag, userLocked);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 6eadd2b..b9d41c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -122,9 +122,6 @@
     private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
     // 1020-1030 reserved for BaseStatusBar
 
-    // will likely move to a resource or other tunable param at some point
-    private static final int HEADS_UP_DECAY_MS = 0; // disabled, was 10000;
-
     private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
 
     private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
@@ -226,6 +223,7 @@
 
     // for heads up notifications
     private HeadsUpNotificationView mHeadsUpNotificationView;
+    private int mHeadsUpNotificationDecay;
 
     // on-screen navigation buttons
     private NavigationBarView mNavigationBarView = null;
@@ -829,7 +827,7 @@
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
-                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar!
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL, // above the status bar!
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                     | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -837,8 +835,8 @@
                     | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                 PixelFormat.TRANSLUCENT);
+        lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
-        //lp.y += height * 1.5; // FIXME
         lp.setTitle("Heads Up");
         lp.packageName = mContext.getPackageName();
         lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp;
@@ -890,26 +888,19 @@
         if (mUseHeadsUp && shouldInterrupt(notification)) {
             if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
             // 1. Populate mHeadsUpNotificationView
+            mInterruptingNotificationTime = System.currentTimeMillis();
+            mInterruptingNotificationEntry = new Entry(key, notification, null);
 
-            // bind the click event to the content area
-            PendingIntent contentIntent = notification.getNotification().contentIntent;
-            final View.OnClickListener listener = (contentIntent != null)
-                    ? new NotificationClicker(contentIntent,
-                    notification.getPackageName(), notification.getTag(), notification.getId())
-                    : null;
-
-            if (mHeadsUpNotificationView.applyContent(notification.getNotification(), listener)) {
-
-                mCurrentlyInterruptingNotification = notification;
-
+            if (inflateViews(mInterruptingNotificationEntry,
+                    mHeadsUpNotificationView.getHolder())) {
+                mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
                 // 2. Animate mHeadsUpNotificationView in
                 mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
 
-                // 3. Set alarm to age the notification off (TODO)
-                mHandler.removeMessages(MSG_HIDE_HEADS_UP);
-                if (HEADS_UP_DECAY_MS > 0) {
-                    mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, HEADS_UP_DECAY_MS);
-                }
+                // 3. Set alarm to age the notification off
+                resetHeadsUpDecayTimer();
+            } else {
+                mInterruptingNotificationEntry = null;
             }
         } else if (notification.getNotification().fullScreenIntent != null) {
             // Stop screensaver if the notification has a full-screen intent.
@@ -926,7 +917,7 @@
             // usual case: status bar visible & not immersive
 
             // show the ticker if there isn't already a heads up
-            if (mCurrentlyInterruptingNotification == null) {
+            if (mInterruptingNotificationEntry == null) {
                 tick(null, notification, true);
             }
         }
@@ -936,6 +927,14 @@
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
     }
 
+    @Override
+    public void resetHeadsUpDecayTimer() {
+        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        if (mHeadsUpNotificationDecay > 0) {
+            mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, mHeadsUpNotificationDecay);
+        }
+    }
+
     public void removeNotification(IBinder key) {
         StatusBarNotification old = removeNotificationViews(key);
         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
@@ -947,7 +946,8 @@
             // Recalculate the position of the sliding windows and the titles.
             updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
 
-            if (ENABLE_HEADS_UP && old == mCurrentlyInterruptingNotification) {
+            if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
+                    && old == mInterruptingNotificationEntry.notification) {
                 mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
             }
 
@@ -1335,7 +1335,7 @@
                     break;
                 case MSG_HIDE_HEADS_UP:
                     setHeadsUpVisibility(false);
-                    mCurrentlyInterruptingNotification = null;
+                    mInterruptingNotificationEntry = null;
                     break;
             }
         }
@@ -2464,14 +2464,14 @@
         mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
     }
 
-    public void dismissHeadsUp() {
-        if (mCurrentlyInterruptingNotification == null) return;
+    public void onHeadsUpDismissed() {
+        if (mInterruptingNotificationEntry == null) return;
 
         try {
             mBarService.onNotificationClear(
-                    mCurrentlyInterruptingNotification.getPackageName(),
-                    mCurrentlyInterruptingNotification.getTag(),
-                    mCurrentlyInterruptingNotification.getId());
+                    mInterruptingNotificationEntry.notification.getPackageName(),
+                    mInterruptingNotificationEntry.notification.getTag(),
+                    mInterruptingNotificationEntry.notification.getId());
         } catch (android.os.RemoteException ex) {
             // oh well
         }
@@ -2555,6 +2555,9 @@
             mNotificationPanelMinHeightFrac = 0f;
         }
 
+        mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
+        mRowHeight =  res.getDimensionPixelSize(R.dimen.notification_row_min_height);
+
         if (false) Log.v(TAG, "updateResources");
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index f6ac4a8..038eba1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -16,11 +16,9 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.app.Notification;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -29,23 +27,32 @@
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
+import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.NotificationData;
 
-public class HeadsUpNotificationView extends LinearLayout implements SwipeHelper.Callback {
+public class HeadsUpNotificationView extends LinearLayout implements SwipeHelper.Callback, ExpandHelper.Callback {
     private static final String TAG = "HeadsUpNotificationView";
     private static final boolean DEBUG = false;
 
     Rect mTmpRect = new Rect();
 
+    private final int mTouchSensitivityDelay;
     private SwipeHelper mSwipeHelper;
 
-    BaseStatusBar mBar;
+    private BaseStatusBar mBar;
+    private ExpandHelper mExpandHelper;
+    private long mStartTouchTime;
+
+    public ViewGroup getHolder() {
+        return mContentHolder;
+    }
+
     private ViewGroup mContentHolder;
 
-    private Notification mHeadsUp;
-    private OnClickListener mOnClickListener;
+    private NotificationData.Entry mHeadsUp;
 
     public HeadsUpNotificationView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -53,8 +60,9 @@
 
     public HeadsUpNotificationView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-
         setOrientation(LinearLayout.VERTICAL);
+        mTouchSensitivityDelay = getResources().getInteger(R.integer.heads_up_sensitivity_delay);
+        if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
     }
 
     @Override
@@ -63,10 +71,14 @@
         float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
 
+        int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
+        int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
+        mExpandHelper = new ExpandHelper(mContext, this, minHeight, maxHeight);
+
         mContentHolder = (ViewGroup) findViewById(R.id.contentHolder);
         if (mHeadsUp != null) {
             // whoops, we're on already!
-            applyContent(mHeadsUp, mOnClickListener);
+            setNotification(mHeadsUp);
         }
     }
 
@@ -77,14 +89,23 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
-        return mSwipeHelper.onInterceptTouchEvent(ev) ||
-            super.onInterceptTouchEvent(ev);
+        if (System.currentTimeMillis() < mStartTouchTime) {
+            return true;
+        }
+        return mSwipeHelper.onInterceptTouchEvent(ev)
+                || mExpandHelper.onInterceptTouchEvent(ev)
+                || super.onInterceptTouchEvent(ev);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        return mSwipeHelper.onTouchEvent(ev) ||
-            super.onTouchEvent(ev);
+        if (System.currentTimeMillis() < mStartTouchTime) {
+            return false;
+        }
+        mBar.resetHeadsUpDecayTimer();
+        return mSwipeHelper.onTouchEvent(ev)
+                || mExpandHelper.onTouchEvent(ev)
+                || super.onTouchEvent(ev);
     }
 
     public boolean canChildBeDismissed(View v) {
@@ -93,7 +114,7 @@
 
     public void onChildDismissed(View v) {
         Log.v(TAG, "User swiped heads up to dismiss");
-        mBar.dismissHeadsUp();
+        mBar.onHeadsUpDismissed();
     }
 
     public void onBeginDrag(View v) {
@@ -134,34 +155,48 @@
         }
     }
 
-    public boolean applyContent(Notification headsUp, OnClickListener listener) {
+    public boolean setNotification(NotificationData.Entry headsUp) {
         mHeadsUp = headsUp;
-        mOnClickListener = listener;
+        mHeadsUp.row.setExpanded(false);
         if (mContentHolder == null) {
             // too soon!
             return false;
         }
-        if (headsUp.contentView == null) {
-            // bad data
-            return false;
-        }
         mContentHolder.setX(0);
         mContentHolder.setVisibility(View.VISIBLE);
         mContentHolder.setAlpha(1f);
         mContentHolder.removeAllViews();
-        final View content = headsUp.contentView.apply(getContext(), mContentHolder);
-        if (listener != null) {
-            content.setOnClickListener(listener);
-
-            Drawable bg = getResources().getDrawable(R.drawable.heads_up_notification_row_bg);
-            if (bg == null) {
-                Log.e(TAG, String.format("Can't find background drawable id=0x%08x",
-                        R.drawable.heads_up_notification_row_bg));
-            } else {
-                content.setBackgroundDrawable(bg);
-            }
-        }
-        mContentHolder.addView(content);
+        mContentHolder.addView(mHeadsUp.row);
+        mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay;
         return true;
     }
+
+    @Override
+    public View getChildAtRawPosition(float x, float y) {
+        return getChildAtPosition(x, y);
+    }
+
+    @Override
+    public View getChildAtPosition(float x, float y) {
+        return mHeadsUp == null ? null : mHeadsUp.row;
+    }
+
+    @Override
+    public boolean canChildBeExpanded(View v) {
+        return mHeadsUp != null && mHeadsUp.row == v && mHeadsUp.row.isExpandable();
+    }
+
+    @Override
+    public void setUserExpandedChild(View v, boolean userExpanded) {
+        if (mHeadsUp != null && mHeadsUp.row == v) {
+            mHeadsUp.row.setUserExpanded(userExpanded);
+        }
+    }
+
+    @Override
+    public void setUserLockedChild(View v, boolean userLocked) {
+        if (mHeadsUp != null && mHeadsUp.row == v) {
+            mHeadsUp.row.setUserLocked(userLocked);
+        }
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 92c57c8..259422d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -32,6 +32,7 @@
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
 
 import java.util.HashMap;
@@ -149,15 +150,20 @@
     }
 
     public boolean canChildBeExpanded(View v) {
-        return NotificationData.getIsExpandable(v);
+        return v instanceof ExpandableNotificationRow
+                && ((ExpandableNotificationRow) v).isExpandable();
     }
 
-    public boolean setUserExpandedChild(View v, boolean userExpanded) {
-        return NotificationData.setUserExpanded(v, userExpanded);
+    public void setUserExpandedChild(View v, boolean userExpanded) {
+        if (v instanceof ExpandableNotificationRow) {
+            ((ExpandableNotificationRow) v).setUserExpanded(userExpanded);
+        }
     }
 
-    public boolean setUserLockedChild(View v, boolean userLocked) {
-        return NotificationData.setUserLocked(v, userLocked);
+    public void setUserLockedChild(View v, boolean userLocked) {
+        if (v instanceof ExpandableNotificationRow) {
+            ((ExpandableNotificationRow) v).setUserLocked(userLocked);
+        }
     }
 
     public void onChildDismissed(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index cf909f3..64a4a0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -137,6 +137,10 @@
     }
 
     @Override
+    public void resetHeadsUpDecayTimer() {
+    }
+
+    @Override
     public void animateExpandSettingsPanel() {
     }
 
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 96de1b9..42b8cce 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -65,11 +65,18 @@
         }
 
         try {
-            mConfig = getIntent().getParcelableExtra("config");
 
             mService = IConnectivityManager.Stub.asInterface(
                     ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
 
+            mConfig = mService.getVpnConfig();
+
+            // mConfig can be null if we are a restricted user, in that case don't show this dialog
+            if (mConfig == null) {
+                finish();
+                return;
+            }
+
             View view = View.inflate(this, R.layout.manage, null);
             if (mConfig.session != null) {
                 ((TextView) view.findViewById(R.id.session)).setText(mConfig.session);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 2460a91..1ea7a7c 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1045,10 +1045,8 @@
         // SystemUI (status bar) layout policy
         int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / density;
 
-        if (shortSizeDp < 600) {
-            // Allow the navigation bar to move on small devices (phones).
-            mNavigationBarCanMove = true;
-        }
+        // Allow the navigation bar to move on small devices (phones).
+        mNavigationBarCanMove = shortSizeDp < 600;
 
         mHasNavigationBar = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_showNavigationBar);
@@ -3231,7 +3229,8 @@
             }
         }
 
-        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
+        // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
+        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR) {
             df.left = df.top = of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
             df.right = df.bottom = of.right = of.bottom = cf.right = cf.bottom
                     = vf.right = vf.bottom = 10000;
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index fab091f..4d70d5f 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -162,7 +162,7 @@
         next(NULL),
         fd(fd), id(id), path(path), identifier(identifier),
         classes(0), configuration(NULL), virtualKeyMap(NULL),
-        ffEffectPlaying(false), ffEffectId(-1),
+        ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
         timestampOverrideSec(0), timestampOverrideUsec(0) {
     memset(keyBitmask, 0, sizeof(keyBitmask));
     memset(absBitmask, 0, sizeof(absBitmask));
@@ -195,7 +195,7 @@
 const int EventHub::EPOLL_MAX_EVENTS;
 
 EventHub::EventHub(void) :
-        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1),
+        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
         mOpeningDevices(0), mClosingDevices(0),
         mNeedToSendFinishedDeviceScan(false),
         mNeedToReopenDevices(false), mNeedToScanDevices(true),
@@ -269,6 +269,13 @@
     return device->classes;
 }
 
+int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
+    AutoMutex _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device == NULL) return 0;
+    return device->controllerNumber;
+}
+
 void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
@@ -1230,6 +1237,10 @@
         device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
     }
 
+    if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_GAMEPAD)) {
+        device->controllerNumber = getNextControllerNumberLocked(device);
+    }
+
     // Register with epoll.
     struct epoll_event eventItem;
     memset(&eventItem, 0, sizeof(eventItem));
@@ -1341,6 +1352,27 @@
     return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH;
 }
 
+int32_t EventHub::getNextControllerNumberLocked(Device* device) {
+    if (mControllerNumbers.isFull()) {
+        ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
+                device->identifier.name.string());
+        return 0;
+    }
+    // Since the controller number 0 is reserved for non-controllers, translate all numbers up by
+    // one
+    return static_cast<int32_t>(mControllerNumbers.markFirstUnmarkedBit() + 1);
+}
+
+void EventHub::releaseControllerNumberLocked(Device* device) {
+    int32_t num = device->controllerNumber;
+    device->controllerNumber= 0;
+    if (num == 0) {
+        return;
+    }
+    mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1));
+}
+
+
 bool EventHub::hasKeycodeLocked(Device* device, int keycode) const {
     if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
         return false;
@@ -1392,6 +1424,8 @@
         }
     }
 
+    releaseControllerNumberLocked(device);
+
     mDevices.removeItem(device->id);
     device->close();
 
@@ -1521,6 +1555,7 @@
             dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
             dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
             dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
+            dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
             dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
             dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
                     "product=0x%04x, version=0x%04x\n",
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index daa1bea..ae28f01 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -33,6 +33,7 @@
 #include <utils/PropertyMap.h>
 #include <utils/Vector.h>
 #include <utils/KeyedVector.h>
+#include <utils/BitSet.h>
 
 #include <linux/input.h>
 #include <sys/epoll.h>
@@ -179,6 +180,8 @@
 
     virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0;
 
+    virtual int32_t getDeviceControllerNumber(int32_t deviceId) const = 0;
+
     virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;
 
     virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
@@ -263,6 +266,8 @@
 
     virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const;
 
+    virtual int32_t getDeviceControllerNumber(int32_t deviceId) const;
+
     virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;
 
     virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
@@ -343,6 +348,8 @@
         bool ffEffectPlaying;
         int16_t ffEffectId; // initially -1
 
+        int32_t controllerNumber;
+
         int32_t timestampOverrideSec;
         int32_t timestampOverrideUsec;
 
@@ -384,6 +391,9 @@
 
     bool isExternalDeviceLocked(Device* device);
 
+    int32_t getNextControllerNumberLocked(Device* device);
+    void releaseControllerNumberLocked(Device* device);
+
     // Protect all internal state.
     mutable Mutex mLock;
 
@@ -398,6 +408,8 @@
 
     int32_t mNextDeviceId;
 
+    BitSet32 mControllerNumbers;
+
     KeyedVector<int32_t, Device*> mDevices;
 
     Device *mOpeningDevices;
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 5b64d8a..feed31c 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -354,8 +354,9 @@
 
     InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
     uint32_t classes = mEventHub->getDeviceClasses(deviceId);
+    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
 
-    InputDevice* device = createDeviceLocked(deviceId, identifier, classes);
+    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
     device->configure(when, &mConfig, 0);
     device->reset(when);
 
@@ -395,10 +396,10 @@
     delete device;
 }
 
-InputDevice* InputReader::createDeviceLocked(int32_t deviceId,
+InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
         const InputDeviceIdentifier& identifier, uint32_t classes) {
     InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
-            identifier, classes);
+            controllerNumber, identifier, classes);
 
     // External devices.
     if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
@@ -843,8 +844,8 @@
 // --- InputDevice ---
 
 InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
-        const InputDeviceIdentifier& identifier, uint32_t classes) :
-        mContext(context), mId(id), mGeneration(generation),
+        int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) :
+        mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber),
         mIdentifier(identifier), mClasses(classes),
         mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
 }
@@ -995,7 +996,8 @@
 }
 
 void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
-    outDeviceInfo->initialize(mId, mGeneration, mIdentifier, mAlias, mIsExternal);
+    outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias,
+            mIsExternal);
 
     size_t numMappers = mMappers.size();
     for (size_t i = 0; i < numMappers; i++) {
@@ -2631,6 +2633,7 @@
             info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat,
                     y.fuzz, y.resolution);
         }
+        info->setButtonUnderPad(mParameters.hasButtonUnderPad);
     }
 }
 
@@ -2796,6 +2799,9 @@
         mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
     }
 
+    mParameters.hasButtonUnderPad=
+            getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD);
+
     String8 deviceTypeString;
     if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
             deviceTypeString)) {
@@ -4650,6 +4656,14 @@
                 mCurrentFingerIdBits, positions);
     }
 
+    // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
+    // to NEUTRAL, then we should not generate tap event.
+    if (mPointerGesture.lastGestureMode != PointerGesture::HOVER
+            && mPointerGesture.lastGestureMode != PointerGesture::TAP
+            && mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) {
+        mPointerGesture.resetTap();
+    }
+
     // Pick a new active touch id if needed.
     // Choose an arbitrary pointer that just went down, if there is one.
     // Otherwise choose an arbitrary remaining pointer.
@@ -4858,8 +4872,12 @@
                 }
             } else {
 #if DEBUG_GESTURES
-                ALOGD("Gestures: Not a TAP, %0.3fms since down",
-                        (when - mPointerGesture.tapDownTime) * 0.000001f);
+                if (mPointerGesture.tapDownTime != LLONG_MIN) {
+                    ALOGD("Gestures: Not a TAP, %0.3fms since down",
+                            (when - mPointerGesture.tapDownTime) * 0.000001f);
+                } else {
+                    ALOGD("Gestures: Not a TAP, incompatible mode transitions");
+                }
 #endif
             }
         }
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 7e303e4..98daaf5 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -409,7 +409,7 @@
 
 protected:
     // These members are protected so they can be instrumented by test cases.
-    virtual InputDevice* createDeviceLocked(int32_t deviceId,
+    virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
             const InputDeviceIdentifier& identifier, uint32_t classes);
 
     class ContextImpl : public InputReaderContext {
@@ -507,16 +507,17 @@
 /* Represents the state of a single input device. */
 class InputDevice {
 public:
-    InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
-            const InputDeviceIdentifier& identifier, uint32_t classes);
+    InputDevice(InputReaderContext* context, int32_t id, int32_t generation, int32_t
+            controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes);
     ~InputDevice();
 
     inline InputReaderContext* getContext() { return mContext; }
-    inline int32_t getId() { return mId; }
-    inline int32_t getGeneration() { return mGeneration; }
-    inline const String8& getName() { return mIdentifier.name; }
-    inline uint32_t getClasses() { return mClasses; }
-    inline uint32_t getSources() { return mSources; }
+    inline int32_t getId() const { return mId; }
+    inline int32_t getControllerNumber() const { return mControllerNumber; }
+    inline int32_t getGeneration() const { return mGeneration; }
+    inline const String8& getName() const { return mIdentifier.name; }
+    inline uint32_t getClasses() const { return mClasses; }
+    inline uint32_t getSources() const { return mSources; }
 
     inline bool isExternal() { return mIsExternal; }
     inline void setExternal(bool external) { mIsExternal = external; }
@@ -573,6 +574,7 @@
 private:
     InputReaderContext* mContext;
     int32_t mId;
+    int32_t mControllerNumber;
     int32_t mGeneration;
     InputDeviceIdentifier mIdentifier;
     String8 mAlias;
@@ -1205,6 +1207,7 @@
         bool hasAssociatedDisplay;
         bool associatedDisplayIsExternal;
         bool orientationAware;
+        bool hasButtonUnderPad;
 
         enum GestureMode {
             GESTURE_MODE_POINTER,
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 14065d2..f068732 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -472,6 +472,10 @@
         return device ? device->identifier : InputDeviceIdentifier();
     }
 
+    virtual int32_t getDeviceControllerNumber(int32_t deviceId) const {
+        return 0;
+    }
+
     virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
         Device* device = getDevice(deviceId);
         if (device) {
@@ -928,22 +932,24 @@
         mNextDevice = device;
     }
 
-    InputDevice* newDevice(int32_t deviceId, const String8& name, uint32_t classes) {
+    InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const String8& name,
+            uint32_t classes) {
         InputDeviceIdentifier identifier;
         identifier.name = name;
         int32_t generation = deviceId + 1;
-        return new InputDevice(&mContext, deviceId, generation, identifier, classes);
+        return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier,
+                classes);
     }
 
 protected:
-    virtual InputDevice* createDeviceLocked(int32_t deviceId,
+    virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
             const InputDeviceIdentifier& identifier, uint32_t classes) {
         if (mNextDevice) {
             InputDevice* device = mNextDevice;
             mNextDevice = NULL;
             return device;
         }
-        return InputReader::createDeviceLocked(deviceId, identifier, classes);
+        return InputReader::createDeviceLocked(deviceId, controllerNumber, identifier, classes);
     }
 
     friend class InputReaderTest;
@@ -988,10 +994,10 @@
         mFakeEventHub->assertQueueIsEmpty();
     }
 
-    FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId,
+    FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
             const String8& name, uint32_t classes, uint32_t sources,
             const PropertyMap* configuration) {
-        InputDevice* device = mReader->newDevice(deviceId, name, classes);
+        InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes);
         FakeInputMapper* mapper = new FakeInputMapper(device, sources);
         device->addMapper(mapper);
         mReader->setNextDevice(device);
@@ -1028,7 +1034,7 @@
 
 TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
     mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
 
@@ -1055,7 +1061,7 @@
 
 TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
     mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN);
 
@@ -1082,7 +1088,7 @@
 
 TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
     mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN);
 
@@ -1109,7 +1115,7 @@
 
 TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
     mapper->addSupportedKeyCode(AKEYCODE_A);
     mapper->addSupportedKeyCode(AKEYCODE_B);
@@ -1153,7 +1159,7 @@
 
 TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
     FakeInputMapper* mapper = NULL;
-    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"),
+    ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
             INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
 
     mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1);
@@ -1177,6 +1183,7 @@
     static const char* DEVICE_NAME;
     static const int32_t DEVICE_ID;
     static const int32_t DEVICE_GENERATION;
+    static const int32_t DEVICE_CONTROLLER_NUMBER;
     static const uint32_t DEVICE_CLASSES;
 
     sp<FakeEventHub> mFakeEventHub;
@@ -1196,7 +1203,7 @@
         InputDeviceIdentifier identifier;
         identifier.name = DEVICE_NAME;
         mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
-                identifier, DEVICE_CLASSES);
+                DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
     }
 
     virtual void TearDown() {
@@ -1212,6 +1219,7 @@
 const char* InputDeviceTest::DEVICE_NAME = "device";
 const int32_t InputDeviceTest::DEVICE_ID = 1;
 const int32_t InputDeviceTest::DEVICE_GENERATION = 2;
+const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0;
 const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD
         | INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK;
 
@@ -1365,6 +1373,7 @@
     static const char* DEVICE_NAME;
     static const int32_t DEVICE_ID;
     static const int32_t DEVICE_GENERATION;
+    static const int32_t DEVICE_CONTROLLER_NUMBER;
     static const uint32_t DEVICE_CLASSES;
 
     sp<FakeEventHub> mFakeEventHub;
@@ -1381,7 +1390,7 @@
         InputDeviceIdentifier identifier;
         identifier.name = DEVICE_NAME;
         mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
-                identifier, DEVICE_CLASSES);
+                DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
 
         mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
     }
@@ -1461,6 +1470,7 @@
 const char* InputMapperTest::DEVICE_NAME = "device";
 const int32_t InputMapperTest::DEVICE_ID = 1;
 const int32_t InputMapperTest::DEVICE_GENERATION = 2;
+const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0;
 const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests
 
 
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index b1489ad..d7cdb9d 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
 import android.app.IAlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -314,7 +315,7 @@
     }
     
     // minimum recurrence period or alarm futurity for us to be able to fuzz it
-    private static final long MAX_FUZZABLE_INTERVAL = 10000;
+    private static final long MIN_FUZZABLE_INTERVAL = 10000;
     private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
     private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
 
@@ -336,7 +337,7 @@
         long futurity = (interval == 0)
                 ? (triggerAtTime - now)
                 : interval;
-        if (futurity < MAX_FUZZABLE_INTERVAL) {
+        if (futurity < MIN_FUZZABLE_INTERVAL) {
             futurity = 0;
         }
         return triggerAtTime + (long)(.75 * futurity);
@@ -499,32 +500,45 @@
     }
 
     @Override
-    public void set(int type, long triggerAtTime, long interval,
-            PendingIntent operation, boolean isExact) {
-        set(type, triggerAtTime, interval, operation, isExact, false);
+    public void set(int type, long triggerAtTime, long windowLength, long interval,
+            PendingIntent operation) {
+        set(type, triggerAtTime, windowLength, interval, operation, false);
     }
 
-    public void set(int type, long triggerAtTime, long interval,
-            PendingIntent operation, boolean isExact, boolean isStandalone) {
+    public void set(int type, long triggerAtTime, long windowLength, long interval,
+            PendingIntent operation, boolean isStandalone) {
         if (operation == null) {
             Slog.w(TAG, "set/setRepeating ignored because there is no intent");
             return;
         }
 
+        // Sanity check the window length.  This will catch people mistakenly
+        // trying to pass an end-of-window timestamp rather than a duration.
+        if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
+            Slog.w(TAG, "Window length " + windowLength
+                    + "ms suspiciously long; limiting to 1 hour");
+            windowLength = AlarmManager.INTERVAL_HOUR;
+        }
+
         if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
             throw new IllegalArgumentException("Invalid alarm type " + type);
         }
 
-        long nowElapsed = SystemClock.elapsedRealtime();
-        long triggerElapsed = convertToElapsed(triggerAtTime, type);
-        long maxElapsed = (isExact)
-                ? triggerElapsed
-                : maxTriggerTime(nowElapsed, triggerElapsed, interval);
+        final long nowElapsed = SystemClock.elapsedRealtime();
+        final long triggerElapsed = convertToElapsed(triggerAtTime, type);
+        final long maxElapsed;
+        if (windowLength == AlarmManager.WINDOW_EXACT) {
+            maxElapsed = triggerElapsed;
+        } else if (windowLength < 0) {
+            maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
+        } else {
+            maxElapsed = triggerElapsed + windowLength;
+        }
 
         synchronized (mLock) {
             if (DEBUG_BATCH) {
                 Slog.v(TAG, "set(" + operation + ") : type=" + type
-                        + " triggerAtTime=" + triggerAtTime
+                        + " triggerAtTime=" + triggerAtTime + " win=" + windowLength
                         + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
                         + " interval=" + interval + " standalone=" + isStandalone);
             }
@@ -1009,15 +1023,15 @@
 
     void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
         final int numBatches = batches.size();
-        for (int i = 0; i < numBatches; i++) {
-            Batch b = batches.get(i);
+        for (int nextBatch = 0; nextBatch < numBatches; nextBatch++) {
+            Batch b = batches.get(nextBatch);
             if (b.start > nowELAPSED) {
                 break;
             }
 
             final int numAlarms = b.alarms.size();
-            for (int j = 0; j < numAlarms; j++) {
-                Alarm a = b.alarms.get(i);
+            for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
+                Alarm a = b.alarms.get(nextAlarm);
                 WakeupEvent e = new WakeupEvent(nowRTC,
                         a.operation.getCreatorUid(),
                         a.operation.getIntent().getAction());
@@ -1218,8 +1232,8 @@
             // the top of the next minute.
             final long tickEventDelay = nextTime - currentTime;
 
-            set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay,
-                    0, mTimeTickSender, true, true);
+            set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
+                    0, mTimeTickSender, true);
         }
 	
         public void scheduleDateChangedEvent() {
@@ -1231,7 +1245,7 @@
             calendar.set(Calendar.MILLISECOND, 0);
             calendar.add(Calendar.DAY_OF_MONTH, 1);
       
-            set(RTC, calendar.getTimeInMillis(), 0, mDateChangeSender, true, true);
+            set(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true);
         }
     }
     
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index d2bae28..f5e75f9 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -42,6 +42,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.net.CaptivePortalTracker;
@@ -96,8 +97,9 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Slog;
-import android.util.SparseIntArray;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.Xml;
 
 import com.android.internal.R;
 import com.android.internal.net.LegacyVpnInfo;
@@ -107,6 +109,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.Nat464Xlat;
@@ -121,7 +124,13 @@
 
 import dalvik.system.DexClassLoader;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.reflect.Constructor;
@@ -170,7 +179,6 @@
     private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
 
     private Tethering mTethering;
-    private boolean mTetheringConfigValid = false;
 
     private KeyStore mKeyStore;
 
@@ -244,6 +252,9 @@
     private static final boolean TO_DEFAULT_TABLE = true;
     private static final boolean TO_SECONDARY_TABLE = false;
 
+    private static final boolean EXEMPT = true;
+    private static final boolean UNEXEMPT = false;
+
     /**
      * used internally as a delayed event to make us switch back to the
      * default network
@@ -341,10 +352,19 @@
 
     private InetAddress mDefaultDns;
 
+    // Lock for protecting access to mAddedRoutes and mExemptAddresses
+    private final Object mRoutesLock = new Object();
+
     // this collection is used to refcount the added routes - if there are none left
     // it's time to remove the route from the route table
+    @GuardedBy("mRoutesLock")
     private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
 
+    // this collection corresponds to the entries of mAddedRoutes that have routing exemptions
+    // used to handle cleanup of exempt rules
+    @GuardedBy("mRoutesLock")
+    private Collection<LinkAddress> mExemptAddresses = new ArrayList<LinkAddress>();
+
     // used in DBG mode to track inet condition reports
     private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
     private ArrayList mInetLog;
@@ -381,6 +401,9 @@
 
     TelephonyManager mTelephonyManager;
 
+    // We only want one checkMobileProvisioning after booting.
+    volatile boolean mFirstProvisioningCheckStarted = false;
+
     public ConnectivityService(Context context, INetworkManagementService netd,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
         // Currently, omitting a NetworkFactory will create one internally
@@ -583,12 +606,8 @@
         }
 
         mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
-        mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
-                                  mTethering.getTetherableWifiRegexs().length != 0 ||
-                                  mTethering.getTetherableBluetoothRegexs().length != 0) &&
-                                 mTethering.getUpstreamIfaceTypes().length != 0);
-        //set up the listener for user state for creating user VPNs
 
+        //set up the listener for user state for creating user VPNs
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_USER_STARTING);
         intentFilter.addAction(Intent.ACTION_USER_STOPPING);
@@ -1463,7 +1482,7 @@
         try {
             InetAddress addr = InetAddress.getByAddress(hostAddress);
             LinkProperties lp = tracker.getLinkProperties();
-            boolean ok = addRouteToAddress(lp, addr);
+            boolean ok = addRouteToAddress(lp, addr, EXEMPT);
             if (DBG) log("requestRouteToHostAddress ok=" + ok);
             return ok;
         } catch (UnknownHostException e) {
@@ -1475,24 +1494,25 @@
         return false;
     }
 
-    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
-        return modifyRoute(p, r, 0, ADD, toDefaultTable);
+    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,
+            boolean exempt) {
+        return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt);
     }
 
     private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
-        return modifyRoute(p, r, 0, REMOVE, toDefaultTable);
+        return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT);
     }
 
-    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
-        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE);
+    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt) {
+        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt);
     }
 
     private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
-        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE);
+        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT);
     }
 
     private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
-            boolean toDefaultTable) {
+            boolean toDefaultTable, boolean exempt) {
         RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
         if (bestRoute == null) {
             bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
@@ -1507,11 +1527,11 @@
                 bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
             }
         }
-        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable);
+        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt);
     }
 
     private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd,
-            boolean toDefaultTable) {
+            boolean toDefaultTable, boolean exempt) {
         if ((lp == null) || (r == null)) {
             if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r);
             return false;
@@ -1540,15 +1560,25 @@
                                                         bestRoute.getGateway(),
                                                         ifaceName);
                 }
-                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
+                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt);
             }
         }
         if (doAdd) {
             if (VDBG) log("Adding " + r + " for interface " + ifaceName);
             try {
                 if (toDefaultTable) {
-                    mAddedRoutes.add(r);  // only track default table - only one apps can effect
-                    mNetd.addRoute(ifaceName, r);
+                    synchronized (mRoutesLock) {
+                        // only track default table - only one apps can effect
+                        mAddedRoutes.add(r);
+                        mNetd.addRoute(ifaceName, r);
+                        if (exempt) {
+                            LinkAddress dest = r.getDestination();
+                            if (!mExemptAddresses.contains(dest)) {
+                                mNetd.setHostExemption(dest);
+                                mExemptAddresses.add(dest);
+                            }
+                        }
+                    }
                 } else {
                     mNetd.addSecondaryRoute(ifaceName, r);
                 }
@@ -1561,18 +1591,25 @@
             // if we remove this one and there are no more like it, then refcount==0 and
             // we can remove it from the table
             if (toDefaultTable) {
-                mAddedRoutes.remove(r);
-                if (mAddedRoutes.contains(r) == false) {
-                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
-                    try {
-                        mNetd.removeRoute(ifaceName, r);
-                    } catch (Exception e) {
-                        // never crash - catch them all
-                        if (VDBG) loge("Exception trying to remove a route: " + e);
-                        return false;
+                synchronized (mRoutesLock) {
+                    mAddedRoutes.remove(r);
+                    if (mAddedRoutes.contains(r) == false) {
+                        if (VDBG) log("Removing " + r + " for interface " + ifaceName);
+                        try {
+                            mNetd.removeRoute(ifaceName, r);
+                            LinkAddress dest = r.getDestination();
+                            if (mExemptAddresses.contains(dest)) {
+                                mNetd.clearHostExemption(dest);
+                                mExemptAddresses.remove(dest);
+                            }
+                        } catch (Exception e) {
+                            // never crash - catch them all
+                            if (VDBG) loge("Exception trying to remove a route: " + e);
+                            return false;
+                        }
+                    } else {
+                        if (VDBG) log("not removing " + r + " as it's still in use");
                     }
-                } else {
-                    if (VDBG) log("not removing " + r + " as it's still in use");
                 }
             } else {
                 if (VDBG) log("Removing " + r + " for interface " + ifaceName);
@@ -2253,6 +2290,7 @@
      */
     private void handleConnectivityChange(int netType, boolean doReset) {
         int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
+        boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType);
 
         /*
          * If a non-default network is enabled, add the host routes that
@@ -2317,7 +2355,7 @@
             }
         }
         mCurrentLinkProperties[netType] = newLp;
-        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
+        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt);
 
         if (resetMask != 0 || resetDns) {
             if (curLp != null) {
@@ -2393,7 +2431,7 @@
      * returns a boolean indicating the routes changed
      */
     private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
-            boolean isLinkDefault) {
+            boolean isLinkDefault, boolean exempt) {
         Collection<RouteInfo> routesToAdd = null;
         CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
         CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
@@ -2429,7 +2467,7 @@
                 }
                 if (newLp != null) {
                     for (InetAddress newDns : newLp.getDnses()) {
-                        addRouteToAddress(newLp, newDns);
+                        addRouteToAddress(newLp, newDns, exempt);
                     }
                 }
             } else {
@@ -2438,28 +2476,30 @@
                     removeRouteToAddress(curLp, oldDns);
                 }
                 for (InetAddress newDns : dnsDiff.added) {
-                    addRouteToAddress(newLp, newDns);
+                    addRouteToAddress(newLp, newDns, exempt);
                 }
             }
         }
 
         for (RouteInfo r :  routeDiff.added) {
             if (isLinkDefault || ! r.isDefaultRoute()) {
-                addRoute(newLp, r, TO_DEFAULT_TABLE);
+                addRoute(newLp, r, TO_DEFAULT_TABLE, exempt);
             } else {
                 // add to a secondary route table
-                addRoute(newLp, r, TO_SECONDARY_TABLE);
+                addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT);
 
                 // many radios add a default route even when we don't want one.
                 // remove the default route unless somebody else has asked for it
                 String ifaceName = newLp.getInterfaceName();
-                if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) {
-                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
-                    try {
-                        mNetd.removeRoute(ifaceName, r);
-                    } catch (Exception e) {
-                        // never crash - catch them all
-                        if (DBG) loge("Exception trying to remove a route: " + e);
+                synchronized (mRoutesLock) {
+                    if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) {
+                        if (VDBG) log("Removing " + r + " for interface " + ifaceName);
+                        try {
+                            mNetd.removeRoute(ifaceName, r);
+                        } catch (Exception e) {
+                            // never crash - catch them all
+                            if (DBG) loge("Exception trying to remove a route: " + e);
+                        }
                     }
                 }
             }
@@ -2579,7 +2619,7 @@
 
     // Caller must grab mDnsLock.
     private void updateDnsLocked(String network, String iface,
-            Collection<InetAddress> dnses, String domains) {
+            Collection<InetAddress> dnses, String domains, boolean defaultDns) {
         int last = 0;
         if (dnses.size() == 0 && mDefaultDns != null) {
             dnses = new ArrayList();
@@ -2591,6 +2631,10 @@
 
         try {
             mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains);
+            if (defaultDns) {
+                mNetd.setDefaultInterfaceForDns(iface);
+            }
+
             for (InetAddress dns : dnses) {
                 ++last;
                 String key = "net.dns" + last;
@@ -2618,7 +2662,7 @@
                 String network = nt.getNetworkInfo().getTypeName();
                 synchronized (mDnsLock) {
                     if (!mDnsOverridden) {
-                        updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains());
+                        updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true);
                     }
                 }
             } else {
@@ -2755,6 +2799,17 @@
                             state + "/" + info.getDetailedState());
                     }
 
+                    // After booting we'll check once for mobile provisioning
+                    // if we've provisioned by and connected.
+                    if (!mFirstProvisioningCheckStarted
+                            && (0 != Settings.Global.getInt(mContext.getContentResolver(),
+                                        Settings.Global.DEVICE_PROVISIONED, 0))
+                            && (state == NetworkInfo.State.CONNECTED)) {
+                        log("check provisioning after booting");
+                        mFirstProvisioningCheckStarted = true;
+                        checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null);
+                    }
+
                     EventLogTags.writeConnectivityStateChanged(
                             info.getType(), info.getSubtype(), info.getDetailedState().ordinal());
 
@@ -3004,7 +3059,10 @@
         int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
         boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.TETHER_SUPPORTED, defaultVal) != 0);
-        return tetherEnabledInSettings && mTetheringConfigValid;
+        return tetherEnabledInSettings && ((mTethering.getTetherableUsbRegexs().length != 0 ||
+                mTethering.getTetherableWifiRegexs().length != 0 ||
+                mTethering.getTetherableBluetoothRegexs().length != 0) &&
+                mTethering.getUpstreamIfaceTypes().length != 0);
     }
 
     // An API NetworkStateTrackers can call when they lose their network.
@@ -3426,6 +3484,20 @@
     }
 
     /**
+     * Returns the information of the ongoing VPN. This method is used by VpnDialogs and
+     * not available in ConnectivityManager.
+     * Permissions are checked in Vpn class.
+     * @hide
+     */
+    @Override
+    public VpnConfig getVpnConfig() {
+        int user = UserHandle.getUserId(Binder.getCallingUid());
+        synchronized(mVpns) {
+            return mVpns.get(user).getVpnConfig();
+        }
+    }
+
+    /**
      * Callback for VPN subsystem. Currently VPN is not adapted to the service
      * through NetworkStateTracker since it works differently. For example, it
      * needs to override DNS servers but never takes the default routes. It
@@ -3475,8 +3547,7 @@
 
             // Apply DNS changes.
             synchronized (mDnsLock) {
-                updateDnsLocked("VPN", iface, addresses, domains);
-                mDnsOverridden = true;
+                updateDnsLocked("VPN", iface, addresses, domains, false);
             }
 
             // Temporarily disable the default proxy (not global).
@@ -3677,6 +3748,8 @@
                 + " resultReceiver=" + resultReceiver);
         enforceChangePermission();
 
+        mFirstProvisioningCheckStarted = true;
+
         int timeOutMs = suggestedTimeOutMs;
         if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) {
             timeOutMs = CheckMp.MAX_TIMEOUT_MS;
@@ -3717,10 +3790,9 @@
                         }
                         case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: {
                             log("CheckMp.onComplete: warm sim");
-                            String url = getProvisioningUrl();
+                            String url = getMobileProvisioningUrl();
                             if (TextUtils.isEmpty(url)) {
-                                url = mContext.getResources()
-                                        .getString(R.string.mobile_redirected_provisioning_url);
+                                url = getMobileRedirectedProvisioningUrl();
                             }
                             if (TextUtils.isEmpty(url) == false) {
                                 log("CheckMp.onComplete: warm sim (redirected), url=" + url);
@@ -3732,7 +3804,7 @@
                         }
                         case ConnectivityManager.CMP_RESULT_CODE_NO_DNS:
                         case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: {
-                            String url = getProvisioningUrl();
+                            String url = getMobileProvisioningUrl();
                             if (TextUtils.isEmpty(url) == false) {
                                 log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url);
                                 setNotificationVisible(true, ni, url);
@@ -4106,10 +4178,114 @@
         log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url);
     }
 
-    private String getProvisioningUrl() {
-        String url = mContext.getResources().getString(R.string.mobile_provisioning_url);
-        log("getProvisioningUrl: mobile_provisioning_url=" + url);
+    /** Location to an updatable file listing carrier provisioning urls.
+     *  An example:
+     *
+     * <?xml version="1.0" encoding="utf-8"?>
+     *  <provisioningUrls>
+     *   <provisioningUrl mcc="310" mnc="4">http://myserver.com/foo?mdn=%3$s&amp;iccid=%1$s&amp;imei=%2$s</provisioningUrl>
+     *   <redirectedUrl mcc="310" mnc="4">http://www.google.com</redirectedUrl>
+     *  </provisioningUrls>
+     */
+    private static final String PROVISIONING_URL_PATH =
+            "/data/misc/radio/provisioning_urls.xml";
+    private final File mProvisioningUrlFile = new File(PROVISIONING_URL_PATH);
 
+    /** XML tag for root element. */
+    private static final String TAG_PROVISIONING_URLS = "provisioningUrls";
+    /** XML tag for individual url */
+    private static final String TAG_PROVISIONING_URL = "provisioningUrl";
+    /** XML tag for redirected url */
+    private static final String TAG_REDIRECTED_URL = "redirectedUrl";
+    /** XML attribute for mcc */
+    private static final String ATTR_MCC = "mcc";
+    /** XML attribute for mnc */
+    private static final String ATTR_MNC = "mnc";
+
+    private static final int REDIRECTED_PROVISIONING = 1;
+    private static final int PROVISIONING = 2;
+
+    private String getProvisioningUrlBaseFromFile(int type) {
+        FileReader fileReader = null;
+        XmlPullParser parser = null;
+        Configuration config = mContext.getResources().getConfiguration();
+        String tagType;
+
+        switch (type) {
+            case PROVISIONING:
+                tagType = TAG_PROVISIONING_URL;
+                break;
+            case REDIRECTED_PROVISIONING:
+                tagType = TAG_REDIRECTED_URL;
+                break;
+            default:
+                throw new RuntimeException("getProvisioningUrlBaseFromFile: Unexpected parameter " +
+                        type);
+        }
+
+        try {
+            fileReader = new FileReader(mProvisioningUrlFile);
+            parser = Xml.newPullParser();
+            parser.setInput(fileReader);
+            XmlUtils.beginDocument(parser, TAG_PROVISIONING_URLS);
+
+            while (true) {
+                XmlUtils.nextElement(parser);
+
+                String element = parser.getName();
+                if (element == null) break;
+
+                if (element.equals(tagType)) {
+                    String mcc = parser.getAttributeValue(null, ATTR_MCC);
+                    try {
+                        if (mcc != null && Integer.parseInt(mcc) == config.mcc) {
+                            String mnc = parser.getAttributeValue(null, ATTR_MNC);
+                            if (mnc != null && Integer.parseInt(mnc) == config.mnc) {
+                                parser.next();
+                                if (parser.getEventType() == XmlPullParser.TEXT) {
+                                    return parser.getText();
+                                }
+                            }
+                        }
+                    } catch (NumberFormatException e) {
+                        loge("NumberFormatException in getProvisioningUrlBaseFromFile: " + e);
+                    }
+                }
+            }
+            return null;
+        } catch (FileNotFoundException e) {
+            loge("Carrier Provisioning Urls file not found");
+        } catch (XmlPullParserException e) {
+            loge("Xml parser exception reading Carrier Provisioning Urls file: " + e);
+        } catch (IOException e) {
+            loge("I/O exception reading Carrier Provisioning Urls file: " + e);
+        } finally {
+            if (fileReader != null) {
+                try {
+                    fileReader.close();
+                } catch (IOException e) {}
+            }
+        }
+        return null;
+    }
+
+    private String getMobileRedirectedProvisioningUrl() {
+        String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING);
+        if (TextUtils.isEmpty(url)) {
+            url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url);
+        }
+        return url;
+    }
+
+    public String getMobileProvisioningUrl() {
+        enforceConnectivityInternalPermission();
+        String url = getProvisioningUrlBaseFromFile(PROVISIONING);
+        if (TextUtils.isEmpty(url)) {
+            url = mContext.getResources().getString(R.string.mobile_provisioning_url);
+            log("getProvisioningUrl: mobile_provisioining_url from resource =" + url);
+        } else {
+            log("getProvisioningUrl: mobile_provisioning_url from File =" + url);
+        }
         // populate the iccid, imei and phone number in the provisioning url.
         if (!TextUtils.isEmpty(url)) {
             String phoneNumber = mTelephonyManager.getLine1Number();
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 7ecd2c0..4c81006 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -1043,7 +1043,7 @@
      */
     public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
         mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+                android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
         enforceCrossUserPermission(userHandle);
 
         DevicePolicyData policy = getUserData(userHandle);
@@ -1146,7 +1146,7 @@
                     return;
                 }
                 mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+                        android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
             }
             long ident = Binder.clearCallingIdentity();
             try {
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index d3dcd69..dfaafb8 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -109,7 +109,7 @@
             android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
 
     private static final String NETWORK_LOCATION_SERVICE_ACTION =
-            "com.android.location.service.v2.NetworkLocationProvider";
+            "com.android.location.service.v3.NetworkLocationProvider";
     private static final String FUSED_LOCATION_SERVICE_ACTION =
             "com.android.location.service.FusedLocationProvider";
 
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index c3a43bb..988b1f2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1473,6 +1473,26 @@
     }
 
     @Override
+    public void setHostExemption(LinkAddress host) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("interface", "fwmark", "exempt", "add", host);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearHostExemption(LinkAddress host) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute("interface", "fwmark", "exempt", "remove", host);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
     public void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index c98a85a..bdf6129 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -75,6 +75,9 @@
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
 
+import com.android.internal.R;
+
+import com.android.internal.notification.NotificationScorer;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -199,6 +202,8 @@
     private static final String TAG_PACKAGE = "package";
     private static final String ATTR_NAME = "name";
 
+    private final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+
     private class NotificationListenerInfo implements DeathRecipient {
         INotificationListener listener;
         ComponentName component;
@@ -707,7 +712,7 @@
             intent.setComponent(name);
 
             intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
-                    com.android.internal.R.string.notification_listener_binding_label);
+                    R.string.notification_listener_binding_label);
             intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
                     mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0));
 
@@ -1297,19 +1302,19 @@
 
         Resources resources = mContext.getResources();
         mDefaultNotificationColor = resources.getColor(
-                com.android.internal.R.color.config_defaultNotificationColor);
+                R.color.config_defaultNotificationColor);
         mDefaultNotificationLedOn = resources.getInteger(
-                com.android.internal.R.integer.config_defaultNotificationLedOn);
+                R.integer.config_defaultNotificationLedOn);
         mDefaultNotificationLedOff = resources.getInteger(
-                com.android.internal.R.integer.config_defaultNotificationLedOff);
+                R.integer.config_defaultNotificationLedOff);
 
         mDefaultVibrationPattern = getLongArray(resources,
-                com.android.internal.R.array.config_defaultNotificationVibePattern,
+                R.array.config_defaultNotificationVibePattern,
                 VIBRATE_PATTERN_MAXLEN,
                 DEFAULT_VIBRATE_PATTERN);
 
         mFallbackVibrationPattern = getLongArray(resources,
-                com.android.internal.R.array.config_notificationFallbackVibePattern,
+                R.array.config_notificationFallbackVibePattern,
                 VIBRATE_PATTERN_MAXLEN,
                 DEFAULT_VIBRATE_PATTERN);
 
@@ -1344,6 +1349,24 @@
 
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
+
+        // spin up NotificationScorers
+        String[] notificationScorerNames = resources.getStringArray(
+                R.array.config_notificationScorers);
+        for (String scorerName : notificationScorerNames) {
+            try {
+                Class<?> scorerClass = mContext.getClassLoader().loadClass(scorerName);
+                NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance();
+                scorer.initialize(mContext);
+                mScorers.add(scorer);
+            } catch (ClassNotFoundException e) {
+                Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e);
+            } catch (InstantiationException e) {
+                Slog.w(TAG, "Couldn't instantiate scorer " + scorerName + ".", e);
+            } catch (IllegalAccessException e) {
+                Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e);
+            }
+        }
     }
 
     /**
@@ -1683,6 +1706,23 @@
 
                 // 3. Apply local rules
 
+                int initialScore = score;
+                if (!mScorers.isEmpty()) {
+                    if (DBG) Slog.v(TAG, "Initial score is " + score + ".");
+                    for (NotificationScorer scorer : mScorers) {
+                        try {
+                            score = scorer.getScore(notification, score);
+                        } catch (Throwable t) {
+                            Slog.w(TAG, "Scorer threw on .getScore.", t);
+                        }
+                    }
+                    if (DBG) Slog.v(TAG, "Final score is " + score + ".");
+                }
+
+                // add extra to indicate score modified by NotificationScorer
+                notification.extras.putBoolean(Notification.EXTRA_SCORE_MODIFIED,
+                        score != initialScore);
+
                 // blocked apps
                 if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
                     if (!isSystemNotification) {
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 795e142..f95532d 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -243,8 +243,9 @@
         }
         r.lastActivity = SystemClock.uptimeMillis();
         r.startRequested = true;
-        if (r.tracker != null) {
-            r.tracker.setStarted(true, mAm.mProcessTracker.getMemFactorLocked(), r.lastActivity);
+        ProcessTracker.ServiceState stracker = r.getTracker();
+        if (stracker != null) {
+            stracker.setStarted(true, mAm.mProcessTracker.getMemFactorLocked(), r.lastActivity);
         }
         r.callStart = false;
         r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
@@ -505,8 +506,9 @@
                 s.lastActivity = SystemClock.uptimeMillis();
                 if (!s.hasAutoCreateConnections()) {
                     // This is the first binding, let the tracker know.
-                    if (s.tracker != null) {
-                        s.tracker.setBound(true, mAm.mProcessTracker.getMemFactorLocked(),
+                    ProcessTracker.ServiceState stracker = s.getTracker();
+                    if (stracker != null) {
+                        stracker.setBound(true, mAm.mProcessTracker.getMemFactorLocked(),
                                 s.lastActivity);
                     }
                 }
@@ -771,12 +773,7 @@
                                 sInfo.applicationInfo.uid, sInfo.packageName,
                                 sInfo.name);
                     }
-                    ProcessTracker.ServiceState tracker = null;
-                    if ((sInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
-                        tracker = mAm.mProcessTracker.getServiceStateLocked(sInfo.packageName,
-                                sInfo.applicationInfo.uid, sInfo.name);
-                    }
-                    r = new ServiceRecord(mAm, ss, name, filter, sInfo, res, tracker);
+                    r = new ServiceRecord(mAm, ss, name, filter, sInfo, res);
                     res.setService(r);
                     mServiceMap.putServiceByName(name, UserHandle.getUserId(r.appInfo.uid), r);
                     mServiceMap.putServiceByIntent(filter, UserHandle.getUserId(r.appInfo.uid), r);
@@ -827,8 +824,9 @@
                 + why + " of " + r.shortName);
         long now = SystemClock.uptimeMillis();
         if (r.executeNesting == 0) {
-            if (r.tracker != null) {
-                r.tracker.setExecuting(true, mAm.mProcessTracker.getMemFactorLocked(), now);
+            ProcessTracker.ServiceState stracker = r.getTracker();
+            if (stracker != null) {
+                stracker.setExecuting(true, mAm.mProcessTracker.getMemFactorLocked(), now);
             }
             if (r.app != null) {
                 if (r.app.executingServices.size() == 0) {
@@ -1340,6 +1338,10 @@
         if (r.tracker != null) {
             r.tracker.setStarted(false, memFactor, now);
             r.tracker.setBound(false, memFactor, now);
+            if (r.executeNesting == 0) {
+                r.tracker.makeInactive();
+                r.tracker = null;
+            }
         }
     }
 
@@ -1500,6 +1502,10 @@
             if (r.tracker != null) {
                 r.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(),
                         SystemClock.uptimeMillis());
+                if (inStopping) {
+                    r.tracker.makeInactive();
+                    r.tracker = null;
+                }
             }
         }
     }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 04ca562..df439e7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -30,6 +30,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.ResolverActivity;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.ProcessStats;
@@ -2049,7 +2050,7 @@
 
     final void setFocusedActivityLocked(ActivityRecord r) {
         if (mFocusedActivity != r) {
-            if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivitiyLocked: r=" + r);
+            if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivityLocked: r=" + r);
             mFocusedActivity = r;
             mStackSupervisor.setFocusedStack(r);
             if (r != null) {
@@ -2486,6 +2487,20 @@
         }
     }
 
+    String getHomePackageName() {
+        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
+        intent.setComponent(mTopComponent);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, mCurrentUserId);
+        if (aInfo != null) {
+            final String homePackageName = aInfo.applicationInfo.packageName;
+            if (!ResolverActivity.class.getName().equals(homePackageName)) {
+                return homePackageName;
+            }
+        }
+        return null;
+    }
+
     boolean startHomeActivityLocked(int userId) {
         if (mHeadless) {
             // Added because none of the other calls to ensureBootCompleted seem to fire
@@ -8315,6 +8330,38 @@
         }
     }
 
+    @Override
+    public void restart() {
+        if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires permission "
+                    + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+        }
+
+        Log.i(TAG, "Sending shutdown broadcast...");
+
+        BroadcastReceiver br = new BroadcastReceiver() {
+            @Override public void onReceive(Context context, Intent intent) {
+                // Now the broadcast is done, finish up the low-level shutdown.
+                Log.i(TAG, "Shutting down activity manager...");
+                shutdown(10000);
+                Log.i(TAG, "Shutdown complete, restarting!");
+                Process.killProcess(Process.myPid());
+                System.exit(10);
+            }
+        };
+
+        // First send the high-level shut down broadcast.
+        Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
+        /* For now we are not doing a clean shutdown, because things seem to get unhappy.
+        mContext.sendOrderedBroadcastAsUser(intent,
+                UserHandle.ALL, null, br, mHandler, 0, null, null);
+        */
+        br.onReceive(mContext, intent);
+    }
+
     public final void startRunning(String pkg, String cls, String action,
             String data) {
         synchronized(this) {
@@ -15493,6 +15540,7 @@
                 final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);
                 stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                 stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
                 final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
                 // This is the result receiver for the final shutdown broadcast.
                 final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index e6849ed..bf3713b 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -80,7 +80,7 @@
     static final int APPLICATION_ACTIVITY_TYPE = 0;
     static final int HOME_ACTIVITY_TYPE = 1;
     static final int RECENTS_ACTIVITY_TYPE = 2;
-    final int mActivityType;
+    int mActivityType;
 
     final String baseDir;   // where activity source (resources etc) located
     final String resDir;   // where public activity source (public resources etc) located
@@ -339,6 +339,10 @@
         }
     }
 
+    boolean isNotResolverActivity() {
+        return !ResolverActivity.class.getName().equals(realActivity.getClassName());
+    }
+
     ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
             int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
             ActivityInfo aInfo, Configuration _configuration,
@@ -442,21 +446,22 @@
 
             // If we know the system has determined the component, then
             // we can consider this to be a home activity...
-            // Note the last check is so we don't count the resolver
-            // activity as being home...  really, we don't care about
-            // doing anything special with something that comes from
-            // the core framework package.
-            if ((!_componentSpecified || _launchedFromUid == Process.myUid()
+            String homePackageName = supervisor.getHomePackageName();
+            if (homePackageName != null && homePackageName.equals(packageName)) {
+                mActivityType = HOME_ACTIVITY_TYPE;
+            } else if ((!_componentSpecified || _launchedFromUid == Process.myUid()
                     || _launchedFromUid == 0) &&
                     Intent.ACTION_MAIN.equals(_intent.getAction()) &&
                     _intent.hasCategory(Intent.CATEGORY_HOME) &&
                     _intent.getCategories().size() == 1 &&
                     _intent.getData() == null &&
                     _intent.getType() == null &&
-                    (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
-                    !ResolverActivity.class.getName().equals(realActivity.getClassName())) {
+                    (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
                 // This sure looks like a home activity!
                 mActivityType = HOME_ACTIVITY_TYPE;
+                if (isNotResolverActivity()) {
+                    supervisor.setHomePackageName(userId, packageName);
+                }
             } else if (realActivity.getClassName().contains("com.android.systemui.recent")) {
                 mActivityType = RECENTS_ACTIVITY_TYPE;
             } else {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a154b9c..dd71044 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -465,7 +465,9 @@
      * Returns the top activity in any existing task matching the given
      * Intent.  Returns null if no such task is found.
      */
-    ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
+    ActivityRecord findTaskLocked(ActivityRecord target) {
+        Intent intent = target.intent;
+        ActivityInfo info = target.info;
         ComponentName cls = intent.getComponent();
         if (info.targetActivity != null) {
             cls = new ComponentName(info.packageName, info.targetActivity);
@@ -474,6 +476,10 @@
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.userId != userId) {
+                // Looking for a different task.
+                continue;
+            }
             final ActivityRecord r = task.getTopActivity();
             if (r == null || r.finishing || r.userId != userId ||
                     r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
@@ -518,7 +524,11 @@
         final int userId = UserHandle.getUserId(info.applicationInfo.uid);
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.userId != mCurrentUser) {
+                return null;
+            }
+            final ArrayList<ActivityRecord> activities = task.mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 ActivityRecord r = activities.get(activityNdx);
                 if (!r.finishing && r.intent.getComponent().equals(cls) && r.userId == userId) {
@@ -534,8 +544,7 @@
     }
 
     /*
-     * Move the activities around in the stack to bring a user to the foreground. This only
-     * matters on the home stack. All other stacks are single user.
+     * Move the activities around in the stack to bring a user to the foreground.
      * @return whether there are any activities for the specified user.
      */
     final boolean switchUserLocked(int userId) {
@@ -1089,6 +1098,9 @@
                                 case RESUMED:
                                 case PAUSING:
                                 case PAUSED:
+                                    // This case created for transitioning activities from
+                                    // translucent to opaque {@link Activity#convertToOpaque}.
+                                    mStackSupervisor.mStoppingActivities.remove(r);
                                     stopActivityLocked(r);
                                     break;
 
@@ -1172,6 +1184,7 @@
             // There are no more activities!  Let's just start up the
             // Launcher...
             ActivityOptions.abort(options);
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return mStackSupervisor.resumeHomeActivity(prev);
         }
@@ -1186,6 +1199,7 @@
             mWindowManager.executeAppTransition();
             mNoAnimActivities.clear();
             ActivityOptions.abort(options);
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Top activity resumed " + next);
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return false;
         }
@@ -1213,6 +1227,7 @@
                 final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
                 mTaskHistory.get(taskNdx).mActivities.get(0).mLaunchHomeTaskNext = true;
             } else {
+                if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next");
                 return mStackSupervisor.resumeHomeActivity(prev);
             }
         }
@@ -1227,6 +1242,7 @@
             mWindowManager.executeAppTransition();
             mNoAnimActivities.clear();
             ActivityOptions.abort(options);
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Going to sleep and all paused");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return false;
         }
@@ -1255,7 +1271,8 @@
         // If we are currently pausing an activity, then don't do anything
         // until that is done.
         if (!mStackSupervisor.allPausedActivitiesComplete()) {
-            if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG, "Skip resume: some activity pausing");
+            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG,
+                    "resumeTopActivityLocked: Skip resume: some activity pausing.");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return false;
         }
@@ -1295,9 +1312,11 @@
         if (mResumedActivity != null) {
             pausing = true;
             startPausingLocked(userLeaving, false);
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);
         }
         if (pausing) {
-            if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
+            if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG,
+                    "resumeTopActivityLocked: Skip resume: need to start pausing");
             // At this point we want to put the upcoming activity's process
             // at the top of the LRU list, since we know we will be needing it
             // very soon and it would be a waste to let it get killed if it
@@ -1459,7 +1478,7 @@
                 // is still at the top and schedule another run if something
                 // weird happened.
                 ActivityRecord nextNext = topRunningActivityLocked(null);
-                if (DEBUG_SWITCH) Slog.i(TAG,
+                if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG,
                         "Activity config changed during resume: " + next
                         + ", new next: " + nextNext);
                 if (nextNext != next) {
@@ -1505,6 +1524,7 @@
 
                 mStackSupervisor.checkReadyForSleepLocked();
 
+                if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Resumed " + next);
             } catch (Exception e) {
                 // Whoops, need to restart this activity!
                 if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to "
@@ -1561,6 +1581,7 @@
                 }
                 if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
             }
+            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Restarting " + next);
             mStackSupervisor.startSpecificActivityLocked(next, true, true);
         }
 
@@ -1568,6 +1589,21 @@
         return true;
     }
 
+    private void insertTaskAtTop(TaskRecord task) {
+        mTaskHistory.remove(task);
+        // Now put task at top.
+        int stackNdx = mTaskHistory.size();
+        if (task.userId != mCurrentUser) {
+            // Put non-current user tasks below current user tasks.
+            while (--stackNdx >= 0) {
+                if (mTaskHistory.get(stackNdx).userId != mCurrentUser) {
+                    break;
+                }
+            }
+            ++stackNdx;
+        }
+        mTaskHistory.add(stackNdx, task);
+    }
 
     final void startActivityLocked(ActivityRecord r, boolean newTask,
             boolean doResume, boolean keepCurTransition, Bundle options) {
@@ -1577,9 +1613,7 @@
             // Last activity in task had been removed or ActivityManagerService is reusing task.
             // Insert or replace.
             // Might not even be in.
-            mTaskHistory.remove(rTask);
-            // Now put task at top.
-            mTaskHistory.add(rTask);
+            insertTaskAtTop(rTask);
             mWindowManager.moveTaskToTop(taskId);
         }
         TaskRecord task = null;
@@ -1599,7 +1633,8 @@
                         r.putInHistory();
                         mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                                 r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
+                                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
+                                r.userId);
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
                         }
@@ -1660,7 +1695,7 @@
             r.updateOptionsLocked(options);
             mWindowManager.addAppToken(task.mActivities.indexOf(r),
                     r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
+                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId);
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
@@ -1703,7 +1738,7 @@
             // because there is nothing for it to animate on top of.
             mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                     r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
+                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId);
             ActivityOptions.abort(options);
         }
         if (VALIDATE_TOKENS) {
@@ -2897,8 +2932,7 @@
 
         // Shift all activities with this task up to the top
         // of the stack, keeping them in the same internal order.
-        mTaskHistory.remove(tr);
-        mTaskHistory.add(tr);
+        insertTaskAtTop(tr);
 
         if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr);
         if (reason != null &&
@@ -3380,7 +3414,7 @@
             printed |= ActivityStackSupervisor.dumpHistoryList(fd, pw,
                     mTaskHistory.get(taskNdx).mActivities, "    ", "Hist", true, !dumpAll,
                     dumpClient, dumpPackage, needSep, header,
-                    "    Task " + taskNdx + ": id #" + task.taskId);
+                    "    Task id #" + task.taskId);
             if (printed) {
                 header = null;
             }
@@ -3448,12 +3482,8 @@
     }
 
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, boolean toTop) {
-        TaskRecord task = new TaskRecord(taskId, info, intent, this);
-        if (toTop) {
-            mTaskHistory.add(task);
-        } else {
-            mTaskHistory.add(0, task);
-        }
+        TaskRecord task = new TaskRecord(taskId, info, intent);
+        addTask(task, toTop);
         return task;
     }
 
@@ -3464,7 +3494,7 @@
     void addTask(final TaskRecord task, final boolean toTop) {
         task.stack = this;
         if (toTop) {
-            mTaskHistory.add(task);
+            insertTaskAtTop(task);
         } else {
             mTaskHistory.add(0, task);
         }
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 8d1a665..925fb3f 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -185,9 +185,6 @@
      * is being brought in front of us. */
     boolean mUserLeaving = false;
 
-    /** Stacks belonging to users other than mCurrentUser. Indexed by userId. */
-    final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
-
     /** Set when we have taken too long waiting to go to sleep. */
     boolean mSleepTimeout = false;
 
@@ -206,6 +203,12 @@
      */
     final PowerManager.WakeLock mGoingToSleep;
 
+    /**
+     * The name of the current home activity for each user.
+     * TODO: Remove entries when user is deleted.
+     */
+    final SparseArray<String> mHomePackageNames = new SparseArray<String>();
+
     public ActivityStackSupervisor(ActivityManagerService service, Context context,
             Looper looper) {
         mService = service;
@@ -263,8 +266,7 @@
     }
 
     boolean isFrontStack(ActivityStack stack) {
-        return (stack.mCurrentUser == mCurrentUser) &&
-                !(stack.isHomeStack() ^ getFocusedStack().isHomeStack());
+        return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack());
     }
 
     void moveHomeStack(boolean toFront) {
@@ -354,7 +356,7 @@
             final int stackId = stack.mStackId;
             final int nextStackId = mWindowManager.removeStack(stackId);
             // TODO: Perhaps we need to let the ActivityManager determine the next focus...
-            if (getFocusedStack().mStackId == stackId) {
+            if (mFocusedStack == null || mFocusedStack.mStackId == stackId) {
                 // If this is the last app stack, set mFocusedStack to null.
                 mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId);
             }
@@ -467,6 +469,8 @@
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             final ActivityStack stack = mStacks.get(stackNdx);
             if (!isFrontStack(stack) && stack.mResumedActivity != null) {
+                if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack +
+                        " mResumedActivity=" + stack.mResumedActivity);
                 stack.startPausingLocked(userLeaving, false);
                 someActivityPaused = true;
             }
@@ -475,16 +479,22 @@
     }
 
     boolean allPausedActivitiesComplete() {
+        boolean pausing = true;
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             final ActivityStack stack = mStacks.get(stackNdx);
             final ActivityRecord r = stack.mPausingActivity;
             if (r != null && r.state != ActivityState.PAUSED
                     && r.state != ActivityState.STOPPED
                     && r.state != ActivityState.STOPPING) {
-                return false;
+                if (DEBUG_STATES) {
+                    Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
+                    pausing = false;
+                } else {
+                    return false;
+                }
             }
         }
-        return true;
+        return pausing;
     }
 
     void reportActivityVisibleLocked(ActivityRecord r) {
@@ -524,8 +534,7 @@
 
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             final ActivityStack stack = mStacks.get(stackNdx);
-            if (stack.mCurrentUser == mCurrentUser && stack != focusedStack &&
-                    isFrontStack(stack)) {
+            if (stack != focusedStack && isFrontStack(stack)) {
                 r = stack.topRunningActivityLocked(null);
                 if (r != null) {
                     return r;
@@ -895,7 +904,7 @@
                         r.userId, System.identityHashCode(r),
                         r.task.taskId, r.shortComponentName);
             }
-            if (r.isHomeActivity()) {
+            if (r.isHomeActivity() && r.isNotResolverActivity()) {
                 mService.mHomeProcess = app;
             }
             mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
@@ -1216,28 +1225,43 @@
         return err;
     }
 
-    ActivityStack getCorrectStack(ActivityRecord r) {
+    ActivityStack adjustStackFocus(ActivityRecord r) {
         final TaskRecord task = r.task;
         if (r.isApplicationActivity() || (task != null && task.isApplicationTask())) {
-            int stackNdx;
-            for (stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) {
-                if (mStacks.get(stackNdx).mCurrentUser == mCurrentUser) {
-                    break;
+            if (task != null) {
+                if (mFocusedStack != task.stack) {
+                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                            "adjustStackFocus: Setting focused stack to r=" + r + " task=" + task);
+                    mFocusedStack = task.stack;
+                } else {
+                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                        "adjustStackFocus: Focused stack already=" + mFocusedStack);
+                }
+                return mFocusedStack;
+            }
+
+            if (mFocusedStack != null) {
+                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                        "adjustStackFocus: Have a focused stack=" + mFocusedStack);
+                return mFocusedStack;
+            }
+
+            for (int stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) {
+                ActivityStack stack = mStacks.get(stackNdx);
+                if (!stack.isHomeStack()) {
+                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                            "adjustStackFocus: Setting focused stack=" + stack);
+                    mFocusedStack = stack;
+                    return mFocusedStack;
                 }
             }
-            if (stackNdx == 0) {
-                // Time to create the first app stack for this user.
-                int stackId = mService.createStack(-1, HOME_STACK_ID,
-                        StackBox.TASK_STACK_GOES_OVER, 1.0f);
-                if (DEBUG_FOCUS) Slog.d(TAG, "getCorrectStack: New stack r=" + r + " stackId="
-                        + stackId);
-                mFocusedStack = getStack(stackId);
-            }
-            if (task != null) {
-                if (DEBUG_FOCUS) Slog.d(TAG, "getCorrectStack: Setting focused stack to r=" +
-                        r + " task=" + task);
-                mFocusedStack = task.stack;
-            }
+
+            // Time to create the first app stack for this user.
+            int stackId = mService.createStack(-1, HOME_STACK_ID,
+                StackBox.TASK_STACK_GOES_OVER, 1.0f);
+            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
+                    " stackId=" + stackId);
+            mFocusedStack = getStack(stackId);
             return mFocusedStack;
         }
         return mHomeStack;
@@ -1256,8 +1280,9 @@
                 mStackState = STACK_STATE_HOME_TO_FRONT;
             }
         } else {
-            if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: Setting focused stack to r=" +
-                    r + " task=" + r.task + " Callers=" + Debug.getCallers(3));
+            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                    "setFocusedStack: Setting focused stack to r=" + r + " task=" + r.task +
+                    " Callers=" + Debug.getCallers(3));
             mFocusedStack = r.task.stack;
             if (mStackState != STACK_STATE_HOME_IN_BACK) {
                 if (DEBUG_STACK) Slog.d(TAG, "setFocusedStack: mStackState old=" +
@@ -1366,7 +1391,7 @@
                 // instance of it in the history, and it is always in its own
                 // unique task, so we do a special search.
                 ActivityRecord intentActivity = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
-                        ? findTaskLocked(intent, r.info)
+                        ? findTaskLocked(r)
                         : findActivityLocked(intent, r.info);
                 if (intentActivity != null) {
                     if (r.task == null) {
@@ -1592,7 +1617,7 @@
         // Should this be considered a new task?
         if (r.resultTo == null && !addingToTask
                 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
-            targetStack = getCorrectStack(r);
+            targetStack = adjustStackFocus(r);
             moveHomeStack(targetStack.isHomeStack());
             if (reuseTask == null) {
                 r.setTask(targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
@@ -1671,7 +1696,7 @@
             // This not being started from an existing activity, and not part
             // of a new task...  just put it in the top task, though these days
             // this case should never happen.
-            targetStack = getCorrectStack(r);
+            targetStack = adjustStackFocus(r);
             moveHomeStack(targetStack.isHomeStack());
             ActivityRecord prev = targetStack.topActivity();
             r.setTask(prev != null ? prev.task
@@ -2009,9 +2034,13 @@
         resumeTopActivitiesLocked();
     }
 
-    ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {
+    ActivityRecord findTaskLocked(ActivityRecord r) {
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityRecord ar = mStacks.get(stackNdx).findTaskLocked(intent, info);
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (!r.isApplicationActivity() && !stack.isHomeStack()) {
+                continue;
+            }
+            final ActivityRecord ar = stack.findTaskLocked(r);
             if (ar != null) {
                 return ar;
             }
@@ -2193,21 +2222,18 @@
     }
 
     boolean switchUserLocked(int userId, UserStartedState uss) {
-        mUserStates.put(mCurrentUser, new UserState());
         mCurrentUser = userId;
-        UserState userState = mUserStates.get(userId);
-        if (userState != null) {
-            userState.restore();
-            mUserStates.delete(userId);
-        } else {
-            mFocusedStack = null;
-            if (DEBUG_STACK) Slog.d(TAG, "switchUserLocked: mStackState=" +
-                    stackStateToString(STACK_STATE_HOME_IN_FRONT));
-            mStackState = STACK_STATE_HOME_IN_FRONT;
+
+        final String homePackageName = mService.getHomePackageName();
+        if (homePackageName != null) {
+            setHomePackageName(mCurrentUser, homePackageName);
         }
 
         mStartingUsers.add(uss);
-        boolean haveActivities = mHomeStack.switchUserLocked(userId);
+        boolean haveActivities = false;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            haveActivities |= mStacks.get(stackNdx).switchUserLocked(userId);
+        }
 
         resumeTopActivitiesLocked();
 
@@ -2304,6 +2330,12 @@
         pw.print(prefix); pw.print("mStackState="); pw.println(stackStateToString(mStackState));
         pw.print(prefix); pw.println("mSleepTimeout: " + mSleepTimeout);
         pw.print(prefix); pw.println("mCurTaskId: " + mCurTaskId);
+        pw.print(prefix); pw.print("mHomePackageNames:");
+                for (int i = 0; i < mHomePackageNames.size(); ++i) {
+                    pw.print(" ("); pw.print(mHomePackageNames.keyAt(i)); pw.print(",");
+                    pw.print(mHomePackageNames.valueAt(i)); pw.print(")");
+                }
+                pw.println();
     }
 
     ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
@@ -2558,22 +2590,13 @@
         }
     }
 
-    private final class UserState {
-        final ActivityStack mSavedFocusedStack;
-        final int mSavedStackState;
+    String getHomePackageName() {
+        return mHomePackageNames.get(mCurrentUser);
+    }
 
-        public UserState() {
-            ActivityStackSupervisor supervisor = ActivityStackSupervisor.this;
-            mSavedFocusedStack = supervisor.mFocusedStack;
-            mSavedStackState = supervisor.mStackState;
-        }
-
-        void restore() {
-            ActivityStackSupervisor supervisor = ActivityStackSupervisor.this;
-            supervisor.mFocusedStack = mSavedFocusedStack;
-            if (DEBUG_STACK) Slog.d(TAG, "UserState.restore: mStackState old=" +
-                    stackStateToString(mSavedStackState));
-            supervisor.mStackState = mSavedStackState;
-        }
+    void setHomePackageName(int userId, String homePackageName) {
+        if (DEBUG_SWITCH) Slog.d(TAG, "setHomePackageName: user=" + userId + " package="
+                + homePackageName);
+        mHomePackageNames.put(userId, homePackageName);
     }
 }
diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java
index ef032ba..416dba5 100644
--- a/services/java/com/android/server/am/ProcessTracker.java
+++ b/services/java/com/android/server/am/ProcessTracker.java
@@ -547,6 +547,8 @@
     }
 
     public static final class ServiceState {
+        int mActive = 1;
+
         final long[] mStartedDurations = new long[ADJ_COUNT];
         int mStartedCount;
         int mStartedState = STATE_NOTHING;
@@ -562,11 +564,30 @@
         int mExecState = STATE_NOTHING;
         long mExecStartTime;
 
+        void makeActive() {
+            mActive++;
+        }
+
+        void makeInactive() {
+            /*
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Slog.i(TAG, "Making " + this + " inactive", here);
+            */
+            mActive--;
+        }
+
+        boolean isActive() {
+            return mActive > 0;
+        }
+
         void resetSafely(long now) {
             for (int i=0; i<ADJ_COUNT; i++) {
                 mStartedDurations[i] = mBoundDurations[i] = mExecDurations[i] = 0;
             }
-            mStartedCount = mBoundCount = mExecCount = 0;
+            mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
+            mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
+            mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
             mStartedStartTime = mBoundStartTime = mExecStartTime = now;
         }
 
@@ -602,6 +623,9 @@
         }
 
         public void setStarted(boolean started, int memFactor, long now) {
+            if (mActive <= 0) {
+                throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
+            }
             int state = started ? memFactor : STATE_NOTHING;
             if (mStartedState != state) {
                 if (mStartedState != STATE_NOTHING) {
@@ -615,6 +639,9 @@
         }
 
         public void setBound(boolean bound, int memFactor, long now) {
+            if (mActive <= 0) {
+                throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
+            }
             int state = bound ? memFactor : STATE_NOTHING;
             if (mBoundState != state) {
                 if (mBoundState != STATE_NOTHING) {
@@ -628,6 +655,9 @@
         }
 
         public void setExecuting(boolean executing, int memFactor, long now) {
+            if (mActive <= 0) {
+                throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
+            }
             int state = executing ? memFactor : STATE_NOTHING;
             if (mExecState != state) {
                 if (mExecState != STATE_NOTHING) {
@@ -687,6 +717,7 @@
 
         final Object mPendingWriteLock = new Object();
         Parcel mPendingWrite;
+        boolean mPendingWriteCommitted;
         long mLastWriteTime;
 
         State(File baseDir, ProcessTracker tracker) {
@@ -718,28 +749,27 @@
             resetCommon();
             long now = SystemClock.uptimeMillis();
             ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-            final int NPROC = procMap.size();
-            for (int ip=0; ip<NPROC; ip++) {
+            for (int ip=procMap.size()-1; ip>=0; ip--) {
                 SparseArray<ProcessState> uids = procMap.valueAt(ip);
-                final int NUID = uids.size();
-                for (int iu=0; iu<NUID; iu++) {
+                for (int iu=uids.size()-1; iu>=0; iu--) {
                     uids.valueAt(iu).resetSafely(now);
                 }
             }
             ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
-            final int NPKG = pkgMap.size();
-            for (int ip=0; ip<NPKG; ip++) {
+            for (int ip=pkgMap.size()-1; ip>=0; ip--) {
                 SparseArray<PackageState> uids = pkgMap.valueAt(ip);
-                final int NUID = uids.size();
-                for (int iu=0; iu<NUID; iu++) {
+                for (int iu=uids.size()-1; iu>=0; iu--) {
                     PackageState pkgState = uids.valueAt(iu);
-                    final int NPROCS = pkgState.mProcesses.size();
-                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                    for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
                         pkgState.mProcesses.valueAt(iproc).resetSafely(now);
                     }
-                    final int NSRVS = pkgState.mServices.size();
-                    for (int isvc=0; isvc<NSRVS; isvc++) {
-                        pkgState.mServices.valueAt(isvc).resetSafely(now);
+                    for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
+                        ServiceState ss = pkgState.mServices.valueAt(isvc);
+                        if (ss.isActive()) {
+                            pkgState.mServices.valueAt(isvc).resetSafely(now);
+                        } else {
+                            pkgState.mServices.removeAt(isvc);
+                        }
                     }
                 }
             }
@@ -756,9 +786,9 @@
             mLongs.add(new long[LONGS_SIZE]);
             mNextLong = 0;
             Arrays.fill(mMemFactorDurations, 0);
-            mMemFactor = STATE_NOTHING;
             mStartTime = 0;
             mReadError = null;
+            mFlags = 0;
         }
 
         private void buildTimePeriodStartClockStr() {
@@ -852,30 +882,40 @@
         private void writeStateLocked(boolean sync, final boolean commit) {
             synchronized (mPendingWriteLock) {
                 long now = SystemClock.uptimeMillis();
-                mPendingWrite = Parcel.obtain();
-                mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
-                writeToParcel(mPendingWrite);
-                mLastWriteTime = SystemClock.uptimeMillis();
+                if (mPendingWrite == null || !mPendingWriteCommitted) {
+                    mPendingWrite = Parcel.obtain();
+                    mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+                    if (commit) {
+                        mFlags |= State.FLAG_COMPLETE;
+                    }
+                    writeToParcel(mPendingWrite);
+                    mPendingWriteCommitted = commit;
+                }
+                if (commit) {
+                    resetSafely();
+                } else {
+                    mLastWriteTime = SystemClock.uptimeMillis();
+                }
                 Slog.i(TAG, "Prepared write state in " + (SystemClock.uptimeMillis()-now) + "ms");
                 if (!sync) {
                     BackgroundThread.getHandler().post(new Runnable() {
                         @Override public void run() {
-                            performWriteState(commit);
+                            performWriteState();
                         }
                     });
                     return;
                 }
             }
 
-            performWriteState(commit);
+            performWriteState();
         }
 
-        void performWriteState(boolean commit) {
-            if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile()
-                    + " commit=" + commit);
+        void performWriteState() {
+            if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile());
             Parcel data;
             synchronized (mPendingWriteLock) {
                 data = mPendingWrite;
+                mPendingWriteCommitted = false;
                 if (data == null) {
                     return;
                 }
@@ -903,9 +943,6 @@
                 }
             }
 
-            if (commit) {
-                resetSafely();
-            }
         }
 
         void writeToParcel(Parcel out) {
@@ -1438,11 +1475,13 @@
         }
 
         void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now) {
+            long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
+                    mStartTime, now);
             dumpFilteredSummaryLocked(pw, null, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
                     new int[] { STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
                             STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
-                            STATE_SERVICE, STATE_RECEIVER, STATE_HOME, STATE_LAST_ACTIVITY },
-                    now, reqPackage);
+                            STATE_SERVICE, STATE_RECEIVER, STATE_HOME },
+                    now, totalTime, reqPackage);
             pw.println();
             pw.println("Run time Stats:");
             dumpSingleTime(pw, "  ", mMemFactorDurations, mMemFactor, mStartTime, now);
@@ -1461,7 +1500,8 @@
         }
 
         void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
-                int[] screenStates, int[] memStates, int[] procStates, long now, String reqPackage) {
+                int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime,
+                String reqPackage) {
             ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
                     procStates, now, reqPackage);
             if (procs.size() > 0) {
@@ -1469,7 +1509,8 @@
                     pw.println();
                     pw.println(header);
                 }
-                dumpProcessSummary(pw, prefix, procs, screenStates, memStates, procStates, now);
+                dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates, procStates,
+                        now, totalTime);
             }
         }
 
@@ -1659,6 +1700,7 @@
         final PackageState as = mState.getPackageStateLocked(packageName, uid);
         ServiceState ss = as.mServices.get(className);
         if (ss != null) {
+            ss.makeActive();
             return ss;
         }
         ss = new ServiceState();
@@ -1684,11 +1726,16 @@
                     ArrayMap<String, ServiceState> services = pkg.mServices;
                     for (int k=0; k<services.size(); k++) {
                         ServiceState service = services.valueAt(k);
-                        if (service.mStartedState != STATE_NOTHING) {
-                            service.setStarted(true, memFactor, now);
-                        }
-                        if (service.mBoundState != STATE_NOTHING) {
-                            service.setBound(true, memFactor, now);
+                        if (service.isActive()) {
+                            if (service.mStartedState != STATE_NOTHING) {
+                                service.setStarted(true, memFactor, now);
+                            }
+                            if (service.mBoundState != STATE_NOTHING) {
+                                service.setBound(true, memFactor, now);
+                            }
+                            if (service.mExecState != STATE_NOTHING) {
+                                service.setExecuting(true, memFactor, now);
+                            }
                         }
                     }
                 }
@@ -1710,7 +1757,6 @@
         if (now > (mState.mLastWriteTime+WRITE_PERIOD)) {
             if (SystemClock.elapsedRealtime() > (mState.mTimePeriodStartRealtime+COMMIT_PERIOD)) {
                 mCommitPending = true;
-                mState.mFlags |= State.FLAG_COMPLETE;
             }
             return true;
         }
@@ -1845,7 +1891,7 @@
         }
     }
 
-    static void dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
+    static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
             int curState, long curStartTime, long now) {
         long totalTime = 0;
         int printedScreen = -1;
@@ -1857,27 +1903,32 @@
                 String running = "";
                 if (curState == state) {
                     time += now - curStartTime;
-                    running = " (running)";
+                    if (pw != null) {
+                        running = " (running)";
+                    }
                 }
                 if (time != 0) {
-                    pw.print(prefix);
-                    printScreenLabel(pw, printedScreen != iscreen
-                            ? iscreen : STATE_NOTHING);
-                    printedScreen = iscreen;
-                    printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
-                    printedMem = imem;
-                    TimeUtils.formatDuration(time, pw); pw.println(running);
+                    if (pw != null) {
+                        pw.print(prefix);
+                        printScreenLabel(pw, printedScreen != iscreen
+                                ? iscreen : STATE_NOTHING);
+                        printedScreen = iscreen;
+                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
+                        printedMem = imem;
+                        TimeUtils.formatDuration(time, pw); pw.println(running);
+                    }
                     totalTime += time;
                 }
             }
         }
-        if (totalTime != 0) {
+        if (totalTime != 0 && pw != null) {
             pw.print(prefix);
             printScreenLabel(pw, STATE_NOTHING);
             pw.print("TOTAL: ");
             TimeUtils.formatDuration(totalTime, pw);
             pw.println();
         }
+        return totalTime;
     }
 
     static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
@@ -1934,8 +1985,16 @@
             procStates = _procStates;
         }
 
-        void print(PrintWriter pw, boolean full) {
-            TimeUtils.formatDuration(totalTime, pw);
+        void print(PrintWriter pw, long overallTime, boolean full) {
+            double percent = ((double)totalTime/(double)overallTime) * 100;
+            if (percent < 1) {
+                pw.print(String.format("%.2f", percent));
+            } else if (percent < 10) {
+                pw.print(String.format("%.1f", percent));
+            } else {
+                pw.print(String.format("%.0f", percent));
+            }
+            pw.print("%");
             if (numPss > 0) {
                 pw.print(" (");
                 printSizeValue(pw, minPss * 1024);
@@ -2075,7 +2134,7 @@
             if (memStates.length > 1) {
                 printMemLabel(pw, STATE_NOTHING);
             }
-            pw.print("TOTAL      : ");
+            pw.print("TOTAL     : ");
             TimeUtils.formatDuration(totalTime, pw);
             pw.println();
         }
@@ -2230,7 +2289,7 @@
 
     static void dumpProcessSummaryDetails(PrintWriter pw, ProcessState proc, String prefix,
             String label, int[] screenStates, int[] memStates, int[] procStates,
-            long now, boolean full) {
+            long now, long totalTime, boolean full) {
         ProcessDataCollection totals = new ProcessDataCollection(screenStates,
                 memStates, procStates);
         computeProcessData(proc, totals, now);
@@ -2241,15 +2300,16 @@
             if (label != null) {
                 pw.print(label);
             }
-            totals.print(pw, full);
+            totals.print(pw, totalTime, full);
             if (prefix != null) {
                 pw.println();
             }
         }
     }
 
-    static void dumpProcessSummary(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
-            int[] screenStates, int[] memStates, int[] procStates, long now) {
+    static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
+            ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
+            long now, long totalTime) {
         for (int i=procs.size()-1; i>=0; i--) {
             ProcessState proc = procs.get(i);
             pw.print(prefix);
@@ -2259,30 +2319,30 @@
             UserHandle.formatUid(pw, proc.mUid);
             pw.println(":");
             dumpProcessSummaryDetails(pw, proc, prefix, "         TOTAL: ", screenStates, memStates,
-                    procStates, now, true);
+                    procStates, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "    Persistent: ", screenStates, memStates,
-                    new int[] { STATE_PERSISTENT }, now, true);
+                    new int[] { STATE_PERSISTENT }, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "           Top: ", screenStates, memStates,
-                    new int[] {STATE_TOP}, now, true);
+                    new int[] {STATE_TOP}, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "        Imp Fg: ", screenStates, memStates,
-                    new int[] { STATE_IMPORTANT_FOREGROUND }, now, true);
+                    new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "        Imp Bg: ", screenStates, memStates,
-                    new int[] {STATE_IMPORTANT_BACKGROUND}, now, true);
+                    new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "        Backup: ", screenStates, memStates,
-                    new int[] {STATE_BACKUP}, now, true);
+                    new int[] {STATE_BACKUP}, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "     Heavy Wgt: ", screenStates, memStates,
-                    new int[] {STATE_HEAVY_WEIGHT}, now, true);
+                    new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "       Service: ", screenStates, memStates,
-                    new int[] {STATE_SERVICE}, now, true);
+                    new int[] {STATE_SERVICE}, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "      Receiver: ", screenStates, memStates,
-                    new int[] {STATE_RECEIVER}, now, true);
+                    new int[] {STATE_RECEIVER}, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "          Home: ", screenStates, memStates,
-                    new int[] {STATE_HOME}, now, true);
-            dumpProcessSummaryDetails(pw, proc, prefix, "      Last Act: ", screenStates, memStates,
-                    new int[] {STATE_LAST_ACTIVITY}, now, true);
+                    new int[] {STATE_HOME}, now, totalTime, true);
+            dumpProcessSummaryDetails(pw, proc, prefix, "    (Last Act): ", screenStates, memStates,
+                    new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
             dumpProcessSummaryDetails(pw, proc, prefix, "      (Cached): ", screenStates, memStates,
                     new int[] {STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_ACTIVITY_CLIENT,
-                            STATE_CACHED_EMPTY}, now, true);
+                            STATE_CACHED_EMPTY}, now, totalTime, true);
         }
     }
 
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 5000940..fe9a71c 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -73,7 +73,6 @@
     final String dataDir;   // where activity data should go
     final boolean exported; // from ServiceInfo.exported
     final Runnable restarter; // used to schedule retries of starting the service
-    final ProcessTracker.ServiceState tracker; // tracking service execution, may be null
     final long createTime;  // when this service was created
     final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
             = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
@@ -84,6 +83,7 @@
 
     ProcessRecord app;      // where this service is running or null.
     ProcessRecord isolatedProc; // keep track of isolated process, if requested
+    ProcessTracker.ServiceState tracker; // tracking service execution, may be null
     boolean isForeground;   // is service currently in foreground mode?
     int foregroundId;       // Notification ID of last foreground req.
     Notification foregroundNoti; // Notification record of foreground state.
@@ -282,8 +282,7 @@
 
     ServiceRecord(ActivityManagerService ams,
             BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
-            Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter,
-            ProcessTracker.ServiceState tracker) {
+            Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) {
         this.ams = ams;
         this.stats = servStats;
         this.name = name;
@@ -299,12 +298,22 @@
         dataDir = sInfo.applicationInfo.dataDir;
         exported = sInfo.exported;
         this.restarter = restarter;
-        this.tracker = tracker;
         createTime = SystemClock.elapsedRealtime();
         lastActivity = SystemClock.uptimeMillis();
         userId = UserHandle.getUserId(appInfo.uid);
     }
 
+    public ProcessTracker.ServiceState getTracker() {
+        if (tracker != null) {
+            return tracker;
+        }
+        if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
+            tracker = ams.mProcessTracker.getServiceStateLocked(serviceInfo.packageName,
+                    serviceInfo.applicationInfo.uid, serviceInfo.name);
+        }
+        return tracker;
+    }
+
     public AppBindRecord retrieveAppBindingLocked(Intent intent,
             ProcessRecord app) {
         Intent.FilterComparison filter = new Intent.FilterComparison(intent);
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index d79211c..63793fa 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -57,13 +57,13 @@
     /** Current stack */
     ActivityStack stack;
 
-    private boolean mApplicationTask = true;
+    /** Takes on same set of values as ActivityRecord.mActivityType */
+    private int mTaskType;
 
-    TaskRecord(int _taskId, ActivityInfo info, Intent _intent, ActivityStack _stack) {
+    TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
         taskId = _taskId;
         affinity = info.taskAffinity;
         setIntent(_intent, info);
-        stack = _stack;
     }
 
     void touchActiveTime() {
@@ -164,9 +164,12 @@
             // Was not previously in list.
             numFullscreen++;
         }
-        // Only set this to be an application task if it has not already been set as home task.
-        if (mApplicationTask) {
-            mApplicationTask = r.isApplicationActivity();
+        // Only set this based on the first activity
+        if (mActivities.isEmpty()) {
+            mTaskType = r.mActivityType;
+        } else {
+            // Otherwise make all added activities match this one.
+            r.mActivityType = mTaskType;
         }
         mActivities.add(index, r);
     }
@@ -320,7 +323,7 @@
     }
 
     boolean isApplicationTask() {
-        return mApplicationTask;
+        return mTaskType == ActivityRecord.APPLICATION_ACTIVITY_TYPE;
     }
 
     public TaskAccessInfo getTaskAccessInfoLocked(boolean inclThumbs) {
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 87263b30..22a7841 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -152,6 +152,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(UsbManager.ACTION_USB_STATE);
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         mContext.registerReceiver(mStateReceiver, filter);
 
         filter = new IntentFilter();
@@ -511,6 +512,8 @@
                     if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");
                     mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
                 }
+            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+                updateConfiguration();
             }
         }
     }
@@ -613,7 +616,7 @@
     public int[] getUpstreamIfaceTypes() {
         int values[];
         synchronized (mPublicSync) {
-            updateConfiguration();
+            updateConfiguration();  // TODO - remove?
             values = new int[mUpstreamIfaceTypes.size()];
             Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator();
             for (int i=0; i < mUpstreamIfaceTypes.size(); i++) {
@@ -1284,7 +1287,7 @@
                 int upType = ConnectivityManager.TYPE_NONE;
                 String iface = null;
 
-                updateConfiguration();
+                updateConfiguration(); // TODO - remove?
 
                 synchronized (mPublicSync) {
                     if (VDBG) {
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 3a2391f..8cc5b4f 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -519,6 +519,14 @@
         }
     }
 
+    /**
+     * Return the configuration of the currently running VPN.
+     */
+    public VpnConfig getVpnConfig() {
+        enforceControlPermission();
+        return mConfig;
+    }
+
     @Deprecated
     public synchronized void interfaceStatusChanged(String iface, boolean up) {
         try {
@@ -610,7 +618,7 @@
 
     private void showNotification(String label, Bitmap icon, int user) {
         if (!mEnableNotif) return;
-        mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext, mConfig);
+        mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
 
         NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 6f57261..7a01219 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -6189,9 +6189,9 @@
         PackageSetting pkgSetting;
         final int uid = Binder.getCallingUid();
         if (UserHandle.getUserId(uid) != userId) {
-            mContext.enforceCallingPermission(
+            mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "setApplicationBlocked for user " + userId);
+                    "setApplicationBlockedSetting for user " + userId);
         }
 
         if (blocked && isPackageDeviceAdmin(packageName, userId)) {
@@ -6224,6 +6224,8 @@
                 return true;
             }
             if (sendRemoved) {
+                killApplication(packageName, UserHandle.getUid(userId, pkgSetting.appId),
+                        "blocking pkg");
                 sendPackageBlockedForUser(packageName, pkgSetting, userId);
             }
         } finally {
@@ -10016,6 +10018,7 @@
                 }
             }
         }
+        sUserManager.systemReady();
     }
 
     public boolean isSafeMode() {
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 2d7d8a0..e6611f0 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1830,6 +1830,20 @@
     }
 
     void readDefaultPreferredAppsLPw(PackageManagerService service, int userId) {
+        // First pull data from any pre-installed apps.
+        for (PackageSetting ps : mPackages.values()) {
+            if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
+                    && ps.pkg.preferredActivityFilters != null) {
+                ArrayList<PackageParser.ActivityIntentInfo> intents
+                        = ps.pkg.preferredActivityFilters;
+                for (int i=0; i<intents.size(); i++) {
+                    PackageParser.ActivityIntentInfo aii = intents.get(i);
+                    applyDefaultPreferredActivityLPw(service, aii, new ComponentName(
+                            ps.name, aii.activity.className), userId);
+                }
+            }
+        }
+
         // Read preferred apps from .../etc/preferred-apps directory.
         File preferredDir = new File(Environment.getRootDirectory(), "etc/preferred-apps");
         if (!preferredDir.exists() || !preferredDir.isDirectory()) {
@@ -1889,6 +1903,166 @@
         }
     }
 
+    private void applyDefaultPreferredActivityLPw(PackageManagerService service,
+            IntentFilter tmpPa, ComponentName cn, int userId) {
+        // The initial preferences only specify the target activity
+        // component and intent-filter, not the set of matches.  So we
+        // now need to query for the matches to build the correct
+        // preferred activity entry.
+        if (PackageManagerService.DEBUG_PREFERRED) {
+            Log.d(TAG, "Processing preferred:");
+            tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), "  ");
+        }
+        Intent intent = new Intent();
+        int flags = 0;
+        intent.setAction(tmpPa.getAction(0));
+        for (int i=0; i<tmpPa.countCategories(); i++) {
+            String cat = tmpPa.getCategory(i);
+            if (cat.equals(Intent.CATEGORY_DEFAULT)) {
+                flags |= PackageManager.MATCH_DEFAULT_ONLY;
+            } else {
+                intent.addCategory(cat);
+            }
+        }
+
+        boolean doNonData = true;
+
+        for (int ischeme=0; ischeme<tmpPa.countDataSchemes(); ischeme++) {
+            boolean doScheme = true;
+            String scheme = tmpPa.getDataScheme(ischeme);
+            for (int issp=0; issp<tmpPa.countDataSchemeSpecificParts(); issp++) {
+                Uri.Builder builder = new Uri.Builder();
+                builder.scheme(scheme);
+                PatternMatcher ssp = tmpPa.getDataSchemeSpecificPart(issp);
+                builder.opaquePart(ssp.getPath());
+                Intent finalIntent = new Intent(intent);
+                finalIntent.setData(builder.build());
+                applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                        scheme, ssp, null, null, null, userId);
+                doScheme = false;
+            }
+            for (int iauth=0; iauth<tmpPa.countDataAuthorities(); iauth++) {
+                boolean doAuth = true;
+                IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(iauth);
+                for (int ipath=0; ipath<tmpPa.countDataPaths(); ipath++) {
+                    Uri.Builder builder = new Uri.Builder();
+                    builder.scheme(scheme);
+                    if (auth.getHost() != null) {
+                        builder.authority(auth.getHost());
+                    }
+                    PatternMatcher path = tmpPa.getDataPath(ipath);
+                    builder.path(path.getPath());
+                    Intent finalIntent = new Intent(intent);
+                    finalIntent.setData(builder.build());
+                    applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                            scheme, null, auth, path, null, userId);
+                    doAuth = doScheme = false;
+                }
+                if (doAuth) {
+                    Uri.Builder builder = new Uri.Builder();
+                    builder.scheme(scheme);
+                    if (auth.getHost() != null) {
+                        builder.authority(auth.getHost());
+                    }
+                    Intent finalIntent = new Intent(intent);
+                    finalIntent.setData(builder.build());
+                    applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                            scheme, null, auth, null, null, userId);
+                    doScheme = false;
+                }
+            }
+            if (doScheme) {
+                Uri.Builder builder = new Uri.Builder();
+                builder.scheme(scheme);
+                Intent finalIntent = new Intent(intent);
+                finalIntent.setData(builder.build());
+                applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                        scheme, null, null, null, null, userId);
+            }
+            doNonData = false;
+        }
+
+        for (int idata=0; idata<tmpPa.countDataTypes(); idata++) {
+            Intent finalIntent = new Intent(intent);
+            String mimeType = tmpPa.getDataType(idata);
+            finalIntent.setType(mimeType);
+            applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                    null, null, null, null, mimeType, userId);
+            doNonData = false;
+        }
+
+        if (doNonData) {
+            applyDefaultPreferredActivityLPw(service, intent, flags, cn,
+                    null, null, null, null, null, userId);
+        }
+    }
+
+    private void applyDefaultPreferredActivityLPw(PackageManagerService service,
+            Intent intent, int flags, ComponentName cn, String scheme, PatternMatcher ssp,
+            IntentFilter.AuthorityEntry auth, PatternMatcher path, String mimeType,
+            int userId) {
+        List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
+                intent.getType(), flags, 0);
+        if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
+                + " results: " + ri);
+        int match = 0;
+        if (ri != null && ri.size() > 1) {
+            boolean haveAct = false;
+            boolean haveNonSys = false;
+            ComponentName[] set = new ComponentName[ri.size()];
+            for (int i=0; i<ri.size(); i++) {
+                ActivityInfo ai = ri.get(i).activityInfo;
+                set[i] = new ComponentName(ai.packageName, ai.name);
+                if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    // If any of the matches are not system apps, then
+                    // there is a third party app that is now an option...
+                    // so don't set a default since we don't want to hide it.
+                    if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+                            + ai.packageName + "/" + ai.name + ": non-system!");
+                    haveNonSys = true;
+                    break;
+                } else if (cn.getPackageName().equals(ai.packageName)
+                        && cn.getClassName().equals(ai.name)) {
+                    if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+                            + ai.packageName + "/" + ai.name + ": default!");
+                    haveAct = true;
+                    match = ri.get(i).match;
+                } else {
+                    if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+                            + ai.packageName + "/" + ai.name + ": skipped");
+                }
+            }
+            if (haveAct && !haveNonSys) {
+                IntentFilter filter = new IntentFilter();
+                if (intent.getAction() != null) {
+                    filter.addAction(intent.getAction());
+                }
+                for (String cat : intent.getCategories()) {
+                    filter.addCategory(cat);
+                }
+                if ((flags&PackageManager.MATCH_DEFAULT_ONLY) != 0) {
+                    filter.addCategory(Intent.CATEGORY_DEFAULT);
+                }
+                if (scheme != null) {
+                    filter.addDataScheme(scheme);
+                }
+                if (ssp != null) {
+                    filter.addDataSchemeSpecificPart(ssp.getPath(), ssp.getType());
+                }
+                if (auth != null) {
+                    filter.addDataAuthority(auth);
+                }
+                if (path != null) {
+                    filter.addDataPath(path);
+                }
+                PreferredActivity pa = new PreferredActivity(filter, match, set, cn);
+                editPreferredActivitiesLPw(userId).addFilter(pa);
+            } else if (!haveNonSys) {
+                Slog.w(TAG, "No component found for default preferred activity " + cn);
+            }
+        }
+    }
+
     private void readDefaultPreferredActivitiesLPw(PackageManagerService service,
             XmlPullParser parser, int userId)
             throws XmlPullParserException, IOException {
@@ -1904,88 +2078,8 @@
             if (tagName.equals(TAG_ITEM)) {
                 PreferredActivity tmpPa = new PreferredActivity(parser);
                 if (tmpPa.mPref.getParseError() == null) {
-                    // The initial preferences only specify the target activity
-                    // component and intent-filter, not the set of matches.  So we
-                    // now need to query for the matches to build the correct
-                    // preferred activity entry.
-                    if (PackageManagerService.DEBUG_PREFERRED) {
-                        Log.d(TAG, "Processing preferred:");
-                        tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), "  ");
-                    }
-                    final ComponentName cn = tmpPa.mPref.mComponent;
-                    Intent intent = new Intent();
-                    int flags = 0;
-                    intent.setAction(tmpPa.getAction(0));
-                    for (int i=0; i<tmpPa.countCategories(); i++) {
-                        String cat = tmpPa.getCategory(i);
-                        if (cat.equals(Intent.CATEGORY_DEFAULT)) {
-                            flags |= PackageManager.MATCH_DEFAULT_ONLY;
-                        } else {
-                            intent.addCategory(cat);
-                        }
-                    }
-                    if (tmpPa.countDataSchemes() > 0) {
-                        Uri.Builder builder = new Uri.Builder();
-                        builder.scheme(tmpPa.getDataScheme(0));
-                        if (tmpPa.countDataSchemeSpecificParts() > 0) {
-                            PatternMatcher path = tmpPa.getDataSchemeSpecificPart(0);
-                            builder.opaquePart(path.getPath());
-                        } else {
-                            if (tmpPa.countDataAuthorities() > 0) {
-                                IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(0);
-                                if (auth.getHost() != null) {
-                                    builder.authority(auth.getHost());
-                                }
-                            }
-                            if (tmpPa.countDataPaths() > 0) {
-                                PatternMatcher path = tmpPa.getDataPath(0);
-                                builder.path(path.getPath());
-                            }
-                        }
-                        intent.setData(builder.build());
-                    } else if (tmpPa.countDataTypes() > 0) {
-                        intent.setType(tmpPa.getDataType(0));
-                    }
-                    List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
-                            intent.getType(), flags, 0);
-                    if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
-                            + " results: " + ri);
-                    int match = 0;
-                    if (ri != null && ri.size() > 1) {
-                        boolean haveAct = false;
-                        boolean haveNonSys = false;
-                        ComponentName[] set = new ComponentName[ri.size()];
-                        for (int i=0; i<ri.size(); i++) {
-                            ActivityInfo ai = ri.get(i).activityInfo;
-                            set[i] = new ComponentName(ai.packageName, ai.name);
-                            if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
-                                // If any of the matches are not system apps, then
-                                // there is a third party app that is now an option...
-                                // so don't set a default since we don't want to hide it.
-                                if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
-                                        + ai.packageName + "/" + ai.name + ": non-system!");
-                                haveNonSys = true;
-                                break;
-                            } else if (cn.getPackageName().equals(ai.packageName)
-                                    && cn.getClassName().equals(ai.name)) {
-                                if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
-                                        + ai.packageName + "/" + ai.name + ": default!");
-                                haveAct = true;
-                                match = ri.get(i).match;
-                            } else {
-                                if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
-                                        + ai.packageName + "/" + ai.name + ": skipped");
-                            }
-                        }
-                        if (haveAct && !haveNonSys) {
-                            PreferredActivity pa = new PreferredActivity(tmpPa, match, set,
-                                    tmpPa.mPref.mComponent);
-                            editPreferredActivitiesLPw(userId).addFilter(pa);
-                        } else if (!haveNonSys) {
-                            Slog.w(TAG, "No component found for default preferred activity "
-                                    + tmpPa.mPref.mComponent);
-                        }
-                    }
+                    applyDefaultPreferredActivityLPw(service, tmpPa, tmpPa.mPref.mComponent,
+                            userId);
                 } else {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Error in package manager settings: <preferred-activity> "
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 2901212..4ead8d5 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -21,11 +21,13 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
 import android.app.IStopUserCallback;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.RestrictionEntry;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
@@ -51,6 +53,7 @@
 import android.util.TimeUtils;
 import android.util.Xml;
 
+import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 
@@ -229,6 +232,13 @@
                 sInstance = this;
             }
         }
+
+    }
+
+    void systemReady() {
+        mUserPackageMonitor.register(ActivityThread.systemMain().getSystemContext(),
+                null, UserHandle.ALL, false);
+        userForeground(UserHandle.USER_OWNER);
     }
 
     @Override
@@ -406,8 +416,15 @@
     @Override
     public void setUserRestrictions(Bundle restrictions, int userId) {
         checkManageUsersPermission("setUserRestrictions");
+        if (restrictions == null) return;
 
         synchronized (mPackagesLock) {
+            // If the user has restrictions already and call is trying to disallow restrictions,
+            // don't modify the flag.
+            if (hasRestrictionsPinLocked(userId)
+                    && restrictions.getBoolean(UserManager.DISALLOW_APP_RESTRICTIONS, false)) {
+                restrictions.putBoolean(UserManager.DISALLOW_APP_RESTRICTIONS, false);
+            }
             mUserRestrictions.get(userId).putAll(restrictions);
             writeUserLocked(mUsers.get(userId));
         }
@@ -671,6 +688,7 @@
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_APP_RESTRICTIONS);
                 serializer.endTag(null, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_USER);
@@ -801,6 +819,7 @@
                         readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
                         readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
                         readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_APP_RESTRICTIONS);
                     }
                 }
             }
@@ -822,11 +841,6 @@
                 pinState.failedAttempts = failedAttempts;
                 pinState.lastAttemptTime = lastAttemptTime;
             }
-            // If this is not a restricted profile and there is no restrictions pin, clean up
-            // any restrictions files that might have been left behind.
-            if (!userInfo.isRestricted() && salt == 0) {
-                cleanAppRestrictions(id);
-            }
             return userInfo;
 
         } catch (IOException ioe) {
@@ -878,11 +892,22 @@
         }
     }
 
+    private boolean isPackageInstalled(String pkg, int userId) {
+        final ApplicationInfo info = mPm.getApplicationInfo(pkg,
+                PackageManager.GET_UNINSTALLED_PACKAGES,
+                userId);
+        if (info == null || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+            return false;
+        }
+        return true;
+    }
+
     /**
-     * Removes all the restrictions files (res_<packagename>) for a given user.
+     * Removes all the restrictions files (res_<packagename>) for a given user, if all is true,
+     * else removes only those packages that have been uninstalled.
      * Does not do any permissions checking.
      */
-    private void cleanAppRestrictions(int userId) {
+    private void cleanAppRestrictions(int userId, boolean all) {
         synchronized (mPackagesLock) {
             File dir = Environment.getUserSystemDirectory(userId);
             String[] files = dir.list();
@@ -891,13 +916,33 @@
                 if (fileName.startsWith(RESTRICTIONS_FILE_PREFIX)) {
                     File resFile = new File(dir, fileName);
                     if (resFile.exists()) {
-                        resFile.delete();
+                        if (all) {
+                            resFile.delete();
+                        } else {
+                            String pkg = fileName.substring(RESTRICTIONS_FILE_PREFIX.length());
+                            if (!isPackageInstalled(pkg, userId)) {
+                                resFile.delete();
+                            }
+                        }
                     }
                 }
             }
         }
     }
 
+    /**
+     * Removes the app restrictions file for a specific package and user id, if it exists.
+     */
+    private void cleanAppRestrictionsForPackage(String pkg, int userId) {
+        synchronized (mPackagesLock) {
+            File dir = Environment.getUserSystemDirectory(userId);
+            File resFile = new File(dir, RESTRICTIONS_FILE_PREFIX + pkg);
+            if (resFile.exists()) {
+                resFile.delete();
+            }
+        }
+    }
+
     @Override
     public UserInfo createUser(String name, int flags) {
         checkManageUsersPermission("Only the system can create users");
@@ -1160,14 +1205,52 @@
     public boolean hasRestrictionsPin() {
         int userId = UserHandle.getCallingUserId();
         synchronized (mPackagesLock) {
-            RestrictionsPinState pinState = mRestrictionsPinStates.get(userId);
-            if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) {
-                return false;
-            }
+            return hasRestrictionsPinLocked(userId);
+        }
+    }
+
+    private boolean hasRestrictionsPinLocked(int userId) {
+        RestrictionsPinState pinState = mRestrictionsPinStates.get(userId);
+        if (pinState == null || pinState.salt == 0 || pinState.pinHash == null) {
+            return false;
         }
         return true;
     }
 
+    @Override
+    public void removeRestrictions() {
+        checkManageUsersPermission("Only system can remove restrictions");
+        final int userHandle = UserHandle.getCallingUserId();
+        synchronized (mPackagesLock) {
+            // Remove all user restrictions
+            setUserRestrictions(new Bundle(), userHandle);
+            // Remove restrictions pin
+            changeRestrictionsPin(null);
+            // Remove any app restrictions
+            cleanAppRestrictions(userHandle, true);
+        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                List<ApplicationInfo> apps =
+                        mPm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES,
+                                userHandle).getList();
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    for (ApplicationInfo appInfo : apps) {
+                        if ((appInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0
+                                && (appInfo.flags & ApplicationInfo.FLAG_BLOCKED) != 0) {
+                            mPm.setApplicationBlockedSettingAsUser(appInfo.packageName, false,
+                                    userHandle);
+                        }
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        });
+    }
+
     /*
      * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
      * Not the most secure, but it is at least a second level of protection. First level is that
@@ -1372,7 +1455,7 @@
     }
 
     /**
-     * Make a note of the last started time of a user.
+     * Make a note of the last started time of a user and do some cleanup.
      * @param userId the user that was just foregrounded
      */
     public void userForeground(int userId) {
@@ -1387,6 +1470,12 @@
                 user.lastLoggedInTime = now;
                 writeUserLocked(user);
             }
+            // If this is not a restricted profile and there is no restrictions pin, clean up
+            // all restrictions files that might have been left behind, else clean up just the
+            // ones with uninstalled packages
+            RestrictionsPinState pinState = mRestrictionsPinStates.get(userId);
+            final long salt = pinState == null ? 0 : pinState.salt;
+            cleanAppRestrictions(userId, (!user.isRestricted() && salt == 0));
         }
     }
 
@@ -1453,4 +1542,17 @@
             }
         }
     }
+
+    private PackageMonitor mUserPackageMonitor = new PackageMonitor() {
+        @Override
+        public void onPackageRemoved(String pkg, int uid) {
+            final int userId = this.getChangingUserId();
+            // Package could be disappearing because it is being blocked, so also check if
+            // it has been uninstalled.
+            final boolean uninstalled = isPackageDisappearing(pkg) == PACKAGE_PERMANENT_CHANGE;
+            if (uninstalled && userId >= 0 && !isPackageInstalled(pkg, userId)) {
+                cleanAppRestrictionsForPackage(pkg, userId);
+            }
+        }
+    };
 }
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
index b9e0280..203bc86 100644
--- a/services/java/com/android/server/print/RemotePrintService.java
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -105,7 +105,7 @@
         throwIfDestroyed();
         if (isBound()) {
             if (DEBUG) {
-                Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnAllPrintJobsHandled");
+                Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnAllPrintJobsHandled()");
             }
             // If bound and all the work is completed, then unbind.
             ensureUnbound();
@@ -342,7 +342,7 @@
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     return service.mSpooler.getPrintJobInfos(service.mComponentName,
-                            PrintJobInfo.STATE_ANY, PrintManager.APP_ID_ANY);
+                            PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS, PrintManager.APP_ID_ANY);
                 } 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 bf2c8e7..6445c2e 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -296,8 +296,7 @@
         }
 
         mContext.bindServiceAsUser(mIntent, mServiceConnection,
-                Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT,
-                    mUserHandle);
+                Context.BIND_AUTO_CREATE, mUserHandle);
 
         final long startMillis = SystemClock.uptimeMillis();
         while (true) {
diff --git a/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java b/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java
new file mode 100644
index 0000000..b53fb65
--- /dev/null
+++ b/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.updates;
+
+public class CarrierProvisioningUrlsInstallReceiver extends ConfigUpdateInstallReceiver {
+
+    public CarrierProvisioningUrlsInstallReceiver() {
+        super("/data/misc/radio/", "provisioning_urls.xml", "metadata/", "version");
+    }
+}
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 088061c..4f699ae 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -25,7 +25,6 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 
@@ -106,8 +105,6 @@
     /** Detect user tapping outside of current focused stack bounds .*/
     Region mTouchExcludeRegion = new Region();
 
-    SparseArray<UserStacks> mUserStacks = new SparseArray<UserStacks>();
-
     /** Save allocating when retrieving tasks */
     ArrayList<Task> mTmpTasks = new ArrayList<Task>();
 
@@ -166,22 +163,6 @@
      */
     ArrayList<Task> getTasks() {
         mTmpTasks.clear();
-        // First do the tasks belonging to other users.
-        final int numUserStacks = mUserStacks.size();
-        for (int i = 0; i < numUserStacks; ++i) {
-            UserStacks userStacks = mUserStacks.valueAt(i);
-            ArrayList<TaskStack> stacks = userStacks.mSavedStackHistory;
-            final int numStacks = stacks.size();
-            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                TaskStack stack = stacks.get(stackNdx);
-                if (stack != mHomeStack) {
-                    if (WindowManagerService.DEBUG_LAYERS) Slog.i(TAG, "getTasks: mStackHistory=" +
-                            mStackHistory);
-                    mTmpTasks.addAll(stack.getTasks());
-                }
-            }
-        }
-        // Now do the current user's tasks.
         final int numStacks = mStackHistory.size();
         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
             mTmpTasks.addAll(mStackHistory.get(stackNdx).getTasks());
@@ -359,14 +340,6 @@
                 return bounds;
             }
         }
-        // Not in the visible stacks, try the saved ones.
-        for (int userNdx = mUserStacks.size() - 1; userNdx >= 0; --userNdx) {
-            UserStacks userStacks = mUserStacks.valueAt(userNdx);
-            Rect bounds = userStacks.mSavedStackBox.getStackBounds(stackId);
-            if (bounds != null) {
-                return bounds;
-            }
-        }
         return null;
     }
 
@@ -400,12 +373,9 @@
                 win.hideLw(false);
             }
         }
-        // Clear the old user's non-home StackBox
-        mUserStacks.put(oldUserId, new UserStacks());
-        UserStacks userStacks = mUserStacks.get(newUserId);
-        if (userStacks != null) {
-            userStacks.restore();
-            mUserStacks.delete(newUserId);
+
+        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
+            mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId);
         }
     }
 
@@ -508,49 +478,6 @@
                   token.dump(pw, "    ");
             }
         }
-        if (mUserStacks.size() > 0) {
-            pw.println();
-            pw.println("  Saved user stacks:");
-            for (int i = 0; i < mUserStacks.size(); ++i) {
-                UserStacks userStacks = mUserStacks.valueAt(i);
-                pw.print("  UserId="); pw.println(Integer.toHexString(mUserStacks.keyAt(i)));
-                pw.print("  StackHistory="); pw.println(userStacks.mSavedStackHistory);
-                pw.print("  StackBox="); userStacks.mSavedStackBox.dump("    ", pw);
-            }
-        }
         pw.println();
     }
-
-    private final class UserStacks {
-        final ArrayList<TaskStack> mSavedStackHistory;
-        StackBox mSavedStackBox;
-        int mBoxNdx;
-
-        public UserStacks() {
-            mSavedStackHistory = new ArrayList<TaskStack>(mStackHistory);
-            for (int stackNdx = mStackHistory.size() - 1; stackNdx >=0; --stackNdx) {
-                if (mStackHistory.get(stackNdx) != mHomeStack) {
-                    mStackHistory.remove(stackNdx);
-                }
-            }
-            mSavedStackBox = null;
-            mBoxNdx = -1;
-            for (int boxNdx = mStackBoxes.size() - 1; boxNdx >= 0; --boxNdx) {
-                StackBox box = mStackBoxes.get(boxNdx);
-                if (box.mStack != mHomeStack) {
-                    mSavedStackBox = box;
-                    mBoxNdx = boxNdx;
-                    mStackBoxes.remove(boxNdx);
-                    break;
-                }
-            }
-        }
-
-        void restore() {
-            mStackHistory = mSavedStackHistory;
-            if (mBoxNdx >= 0) {
-                mStackBoxes.add(mBoxNdx, mSavedStackBox);
-            }
-        }
-    }
 }
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
index d352464..d4cf4e2 100644
--- a/services/java/com/android/server/wm/StackBox.java
+++ b/services/java/com/android/server/wm/StackBox.java
@@ -109,8 +109,8 @@
      * @return true if the specified StackBox matches this or one of its descendants.
      */
     boolean contains(int stackBoxId) {
-        return mStackBoxId == stackBoxId || mFirst.contains(stackBoxId)
-                || mSecond.contains(stackBoxId);
+        return mStackBoxId == stackBoxId ||
+                (mStack == null &&  (mFirst.contains(stackBoxId) || mSecond.contains(stackBoxId)));
     }
 
     /**
@@ -371,6 +371,15 @@
         mSecond.stopDimmingIfNeeded();
     }
 
+    void switchUserStacks(int userId) {
+        if (mStack != null) {
+            mStack.switchUser(userId);
+            return;
+        }
+        mFirst.switchUserStacks(userId);
+        mSecond.switchUserStacks(userId);
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mParent="); pw.println(mParent);
         pw.print(prefix); pw.print("mBounds="); pw.print(mBounds.toShortString());
diff --git a/services/java/com/android/server/wm/Task.java b/services/java/com/android/server/wm/Task.java
index 88eb96e..d9acbb9 100644
--- a/services/java/com/android/server/wm/Task.java
+++ b/services/java/com/android/server/wm/Task.java
@@ -21,11 +21,13 @@
     TaskStack mStack;
     final AppTokenList mAppTokens = new AppTokenList();
     final int taskId;
+    final int mUserId;
 
-    Task(AppWindowToken wtoken, TaskStack stack) {
+    Task(AppWindowToken wtoken, TaskStack stack, int userId) {
         taskId = wtoken.groupId;
         mAppTokens.add(wtoken);
         mStack = stack;
+        mUserId = userId;
     }
 
     DisplayContent getDisplayContent() {
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java
index 18019e6..29156be 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/java/com/android/server/wm/TaskStack.java
@@ -97,9 +97,28 @@
      * @param toTop Whether to add it to the top or bottom.
      */
     boolean addTask(Task task, boolean toTop) {
-        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop);
         mStackBox.makeDirty();
-        mTasks.add(toTop ? mTasks.size() : 0, task);
+
+        int stackNdx;
+        if (!toTop) {
+            stackNdx = 0;
+        } else {
+            stackNdx = mTasks.size();
+            final int currentUserId = mService.mCurrentUserId;
+            if (task.mUserId != currentUserId) {
+                // Place the task below all current user tasks.
+                while (--stackNdx >= 0) {
+                    if (currentUserId != mTasks.get(stackNdx).mUserId) {
+                        break;
+                    }
+                }
+                ++stackNdx;
+            }
+        }
+        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop
+                + " pos=" + stackNdx);
+        mTasks.add(stackNdx, task);
+
         task.mStack = this;
         return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID);
     }
@@ -256,6 +275,18 @@
         }
     }
 
+    void switchUser(int userId) {
+        int top = mTasks.size();
+        for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
+            Task task = mTasks.get(taskNdx);
+            if (task.mUserId == userId) {
+                mTasks.remove(taskNdx);
+                mTasks.add(task);
+                --top;
+            }
+        }
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
         for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index afdbc87..2688cff 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -542,7 +542,7 @@
         boolean hasPendingLayoutChanges = false;
         final int numDisplays = mService.mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mService.mDisplayContents.get(displayNdx);
+            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
             final int pendingChanges = getPendingLayoutChanges(displayContent.getDisplayId());
             if ((pendingChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
                 mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index d741d77..f763068 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3374,7 +3374,7 @@
 
     @Override
     public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
-            int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
+            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3407,7 +3407,7 @@
             atoken.showWhenLocked = showWhenLocked;
             atoken.requestedOrientation = requestedOrientation;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
-                    + " at " + addPos);
+                    + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
 
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
@@ -3415,7 +3415,7 @@
                 if (stack == null) {
                     throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
                 }
-                task = new Task(atoken, stack);
+                task = new Task(atoken, stack, userId);
                 stack.addTask(task, true);
                 stack.getDisplayContent().moveStack(stack, true);
                 mTaskIdToTask.put(taskId, task);
@@ -5072,13 +5072,11 @@
             throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
         }
 
-        if (scale < 0) scale = 0;
-        else if (scale > 20) scale = 20;
-        scale = Math.abs(scale);
+        scale = fixScale(scale);
         switch (which) {
-            case 0: mWindowAnimationScale = fixScale(scale); break;
-            case 1: mTransitionAnimationScale = fixScale(scale); break;
-            case 2: mAnimatorDurationScale = fixScale(scale); break;
+            case 0: mWindowAnimationScale = scale; break;
+            case 1: mTransitionAnimationScale = scale; break;
+            case 2: mAnimatorDurationScale = scale; break;
         }
 
         // Persist setting
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index ed74fdf..aca77b8 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -878,7 +878,7 @@
         mAlarmManager.remove(isA(PendingIntent.class));
         expectLastCall().anyTimes();
 
-        mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class), false);
+        mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), isA(PendingIntent.class));
         expectLastCall().atLeastOnce();
 
         mNetManager.setGlobalAlert(anyLong());
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 53318a4..e4c4214 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
         }
         
         try {
-            mWm.addAppToken(0, null, 0, 0, 0, false, false);
+            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 6343049..f0c3a75 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -81,7 +81,7 @@
 
     @Override
     public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
-            boolean arg5, boolean arg6)
+            boolean arg5, boolean arg6, int arg7)
             throws RemoteException {
         // TODO Auto-generated method stub
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index cbefd3d..b909bec 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -30,6 +30,7 @@
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.resources.Density;
 import com.android.resources.ResourceType;
+import com.android.resources.ScreenOrientation;
 import com.android.resources.ScreenSize;
 
 import android.content.res.Configuration;
@@ -347,6 +348,23 @@
         config.compatScreenWidthDp = config.screenWidthDp;
         config.compatScreenHeightDp = config.screenHeightDp;
 
+        ScreenOrientation orientation = hardwareConfig.getOrientation();
+        if (orientation != null) {
+            switch (orientation) {
+            case PORTRAIT:
+                config.orientation = Configuration.ORIENTATION_PORTRAIT;
+                break;
+            case LANDSCAPE:
+                config.orientation = Configuration.ORIENTATION_LANDSCAPE;
+                break;
+            case SQUARE:
+                config.orientation = Configuration.ORIENTATION_SQUARE;
+                break;
+            }
+        } else {
+            config.orientation = Configuration.ORIENTATION_UNDEFINED;
+        }
+
         // TODO: fill in more config info.
 
         return config;