Cara menggunakan setduration in javascript

larutan

animasi alpha android menghapus alpha (android alpha animation remove alpha)

Show

    Saya memiliki Imageview di file Xml saya dan saya memiliki 0.6f alpha di imageview saya. ini adalah kode

     <ImageView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:scaleType="centerCrop"
      android:alpha=".60"
      android:id="@+id/u_go_dashboard_bill"/>
    

    sekarang saya ingin menghapus alpha dengan animasi dengan fade in fade out .i mean alpha 100 %.i juga menulis beberapa kode java tetapi saya tidak dapat mengubahnya

      AlphaAnimation alpha = new AlphaAnimation(0.0F, 1.0F);
                alpha.setDuration(150);
                alpha.setFillAfter(true);
                dashboardBillAvatar.startAnimation(alpha);
    

    bagaimana saya dapat memecahkan masalah saya? jika ada yang tahu solusinya tolong bantu saya ps saya tidak pernah mengerjakan animasi alfa dan saya tidak tahu caranya saya bisa menggunakannya terima kasih semuanya


    larutan

    larutan 1:

    Try this:

    ImageView yourImageView = (ImageView) findViewById(R.id.u_go_dashboard_bill);
    yourImageView.animate().alpha(1.0).setDuration(150).start();
    

    (by donoachua、Vitaly Zinchenko)

    larutan

    1. android alpha animation remove alpha (CC BY‑SA 2.5/3.0/4.0)

    #fadeOut #alpha #fadeIn #android-animation #Android

    Merge "FLAG_DISMISS_KEYGUARD should not hide status bar if secure." into jb-mr2-dev
    diff --git a/api/current.txt b/api/current.txt
    index 2f79c9b..d1be295 100644
    --- a/api/current.txt
    +++ b/api/current.txt
    
    @@ -852,6 +852,7 @@
         field public static final int reqNavigation = 16843306; // 0x101022a
         field public static final int reqTouchScreen = 16843303; // 0x1010227
         field public static final int required = 16843406; // 0x101028e
    +    field public static final int requiredAccountType = 16843734; // 0x10103d6
         field public static final int requiredForAllUsers = 16843728; // 0x10103d0
         field public static final int requiresFadingEdge = 16843685; // 0x10103a5
         field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
    @@ -2305,22 +2306,28 @@
     
     package android.animation {
     
    -  public abstract class Animator implements java.lang.Cloneable {
    +  public abstract interface Animatable {
    +    method public abstract long getDuration();
    +    method public abstract android.animation.TimeInterpolator getInterpolator();
    +    method public abstract long getStartDelay();
    +    method public abstract android.animation.Animatable setDuration(long);
    +    method public abstract void setInterpolator(android.animation.TimeInterpolator);
    +    method public abstract void setStartDelay(long);
    +  }
    +
    +  public abstract class Animator implements android.animation.Animatable java.lang.Cloneable {
         ctor public Animator();
         method public void addListener(android.animation.Animator.AnimatorListener);
         method public void cancel();
         method public android.animation.Animator clone();
         method public void end();
    -    method public abstract long getDuration();
    +    method public android.animation.TimeInterpolator getInterpolator();
         method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
    -    method public abstract long getStartDelay();
         method public abstract boolean isRunning();
         method public boolean isStarted();
         method public void removeAllListeners();
         method public void removeListener(android.animation.Animator.AnimatorListener);
         method public abstract android.animation.Animator setDuration(long);
    -    method public abstract void setInterpolator(android.animation.TimeInterpolator);
    -    method public abstract void setStartDelay(long);
         method public void setTarget(java.lang.Object);
         method public void setupEndValues();
         method public void setupStartValues();
    @@ -2511,7 +2518,6 @@
         method public long getCurrentPlayTime();
         method public long getDuration();
         method public static long getFrameDelay();
    -    method public android.animation.TimeInterpolator getInterpolator();
         method public int getRepeatCount();
         method public int getRepeatMode();
         method public long getStartDelay();
    @@ -4190,6 +4196,7 @@
         method public final boolean performGlobalAction(int);
         method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
         method public boolean setRotation(int);
    +    method public void setRunAsMonkey(boolean);
         method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
         method public android.graphics.Bitmap takeScreenshot();
         method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
    @@ -11810,10 +11817,10 @@
         method public void seekTo(long, int);
         method public void selectTrack(int);
         method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
    -    method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
    -    method public final void setDataSource(java.lang.String);
    -    method public final void setDataSource(java.io.FileDescriptor);
    -    method public final void setDataSource(java.io.FileDescriptor, long, long);
    +    method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
    +    method public final void setDataSource(java.lang.String) throws java.io.IOException;
    +    method public final void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
    +    method public final void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
         method public void unselectTrack(int);
         field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
         field public static final int SAMPLE_FLAG_SYNC = 1; // 0x1
    @@ -12260,13 +12267,17 @@
         ctor public RemoteControlClient(android.app.PendingIntent);
         ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
         method public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean);
    +    method public void setOnGetPlaybackPositionListener(android.media.RemoteControlClient.OnGetPlaybackPositionListener);
    +    method public void setPlaybackPositionUpdateListener(android.media.RemoteControlClient.OnPlaybackPositionUpdateListener);
         method public void setPlaybackState(int);
    +    method public void setPlaybackState(int, long, float);
         method public void setTransportControlFlags(int);
         field public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
         field public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
         field public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
         field public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
         field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
    +    field public static final int FLAG_KEY_MEDIA_POSITION_UPDATE = 256; // 0x100
         field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
         field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
         field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
    @@ -12290,6 +12301,14 @@
         field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
       }
     
    +  public static abstract interface RemoteControlClient.OnGetPlaybackPositionListener {
    +    method public abstract long onGetPlaybackPosition();
    +  }
    +
    +  public static abstract interface RemoteControlClient.OnPlaybackPositionUpdateListener {
    +    method public abstract void onPlaybackPositionUpdate(long);
    +  }
    +
       public class Ringtone {
         method public int getStreamType();
         method public java.lang.String getTitle(android.content.Context);
    @@ -17074,18 +17093,20 @@
         method public java.lang.String getUserName();
         method public android.os.Bundle getUserRestrictions();
         method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
    +    method public boolean isLinkedUser();
         method public boolean isUserAGoat();
    -    method public boolean isUserRestricted();
         method public boolean isUserRunning(android.os.UserHandle);
         method public boolean isUserRunningOrStopping(android.os.UserHandle);
         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_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";
         field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
         field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
         field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
    +    field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
         field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
         field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
         field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
    @@ -20001,6 +20022,35 @@
         method public void reset();
         method public void reset(int);
         method public void skip(int);
    +    method public boolean subBoolean();
    +    method public android.renderscript.Byte2 subByte2();
    +    method public android.renderscript.Byte3 subByte3();
    +    method public android.renderscript.Byte4 subByte4();
    +    method public android.renderscript.Double2 subDouble2();
    +    method public android.renderscript.Double3 subDouble3();
    +    method public android.renderscript.Double4 subDouble4();
    +    method public float subF32();
    +    method public double subF64();
    +    method public android.renderscript.Float2 subFloat2();
    +    method public android.renderscript.Float3 subFloat3();
    +    method public android.renderscript.Float4 subFloat4();
    +    method public short subI16();
    +    method public int subI32();
    +    method public long subI64();
    +    method public byte subI8();
    +    method public android.renderscript.Int2 subInt2();
    +    method public android.renderscript.Int3 subInt3();
    +    method public android.renderscript.Int4 subInt4();
    +    method public android.renderscript.Long2 subLong2();
    +    method public android.renderscript.Long3 subLong3();
    +    method public android.renderscript.Long4 subLong4();
    +    method public android.renderscript.Matrix2f subMatrix2f();
    +    method public android.renderscript.Matrix3f subMatrix3f();
    +    method public android.renderscript.Matrix4f subMatrix4f();
    +    method public android.renderscript.Short2 subShort2();
    +    method public android.renderscript.Short3 subShort3();
    +    method public android.renderscript.Short4 subShort4();
    +    method public void subalign(int);
       }
     
       public class Float2 {
    @@ -20160,11 +20210,13 @@
       public class RenderScript {
         method public void contextDump();
         method public static android.renderscript.RenderScript create(android.content.Context);
    +    method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType);
         method public void destroy();
         method public void finish();
         method public final android.content.Context getApplicationContext();
         method public android.renderscript.RenderScript.RSErrorHandler getErrorHandler();
         method public android.renderscript.RenderScript.RSMessageHandler getMessageHandler();
    +    method public void sendMessage(int, int[]);
         method public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler);
         method public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler);
         method public void setPriority(android.renderscript.RenderScript.Priority);
    @@ -20245,6 +20297,12 @@
         method protected android.renderscript.Script.KernelID createKernelID(int, int, android.renderscript.Element, android.renderscript.Element);
         method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker);
         method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions);
    +    method public boolean getVarB(int);
    +    method public double getVarD(int);
    +    method public float getVarF(int);
    +    method public int getVarI(int);
    +    method public long getVarJ(int);
    +    method public void getVarV(int, android.renderscript.FieldPacker);
         method protected void invoke(int);
         method protected void invoke(int, android.renderscript.FieldPacker);
         method public void setTimeZone(java.lang.String);
    @@ -20321,6 +20379,13 @@
       public abstract class ScriptIntrinsic extends android.renderscript.Script {
       }
     
    +  public final class ScriptIntrinsic3DLUT extends android.renderscript.ScriptIntrinsic {
    +    method public static android.renderscript.ScriptIntrinsic3DLUT create(android.renderscript.RenderScript, android.renderscript.Element);
    +    method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation);
    +    method public android.renderscript.Script.KernelID getKernelID();
    +    method public void setLUT(android.renderscript.Allocation);
    +  }
    +
       public class ScriptIntrinsicBlend extends android.renderscript.ScriptIntrinsic {
         method public static android.renderscript.ScriptIntrinsicBlend create(android.renderscript.RenderScript, android.renderscript.Element);
         method public void forEachAdd(android.renderscript.Allocation, android.renderscript.Allocation);
    @@ -20440,6 +20505,7 @@
         method public android.renderscript.Element getElement();
         method public int getX();
         method public int getY();
    +    method public int getYuv();
         method public int getZ();
         method public boolean hasFaces();
         method public boolean hasMipmaps();
    @@ -20452,6 +20518,7 @@
         method public android.renderscript.Type.Builder setMipmaps(boolean);
         method public android.renderscript.Type.Builder setX(int);
         method public android.renderscript.Type.Builder setY(int);
    +    method public android.renderscript.Type.Builder setYuvFormat(int);
         method public android.renderscript.Type.Builder setZ(int);
       }
     
    @@ -20513,19 +20580,37 @@
     
     package android.security {
     
    -  public class AndroidKeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
    +  public final class AndroidKeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
    +    method public android.content.Context getContext();
    +    method public java.util.Date getEndDate();
    +    method public java.lang.String getKeystoreAlias();
    +    method public java.math.BigInteger getSerialNumber();
    +    method public java.util.Date getStartDate();
    +    method public javax.security.auth.x500.X500Principal getSubjectDN();
    +    method public boolean isEncryptionRequired();
       }
     
    -  public static class AndroidKeyPairGeneratorSpec.Builder {
    +  public static final class AndroidKeyPairGeneratorSpec.Builder {
         ctor public AndroidKeyPairGeneratorSpec.Builder(android.content.Context);
         method public android.security.AndroidKeyPairGeneratorSpec build();
         method public android.security.AndroidKeyPairGeneratorSpec.Builder setAlias(java.lang.String);
    +    method public android.security.AndroidKeyPairGeneratorSpec.Builder setEncryptionRequired();
         method public android.security.AndroidKeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
         method public android.security.AndroidKeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
         method public android.security.AndroidKeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
         method public android.security.AndroidKeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
       }
     
    +  public final class AndroidKeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
    +    method public boolean isEncryptionRequired();
    +  }
    +
    +  public static final class AndroidKeyStoreParameter.Builder {
    +    ctor public AndroidKeyStoreParameter.Builder(android.content.Context);
    +    method public android.security.AndroidKeyStoreParameter build();
    +    method public android.security.AndroidKeyStoreParameter.Builder setEncryptionRequired();
    +  }
    +
       public final class KeyChain {
         ctor public KeyChain();
         method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
    @@ -25295,6 +25380,7 @@
         method protected float getBottomFadingEdgeStrength();
         method protected int getBottomPaddingOffset();
         method public float getCameraDistance();
    +    method public android.graphics.Rect getClipBounds();
         method public java.lang.CharSequence getContentDescription();
         method public final android.content.Context getContext();
         method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
    @@ -25549,6 +25635,7 @@
         method public final void setBottom(int);
         method public void setCameraDistance(float);
         method public void setClickable(boolean);
    +    method public void setClipBounds(android.graphics.Rect);
         method public void setContentDescription(java.lang.CharSequence);
         method public void setDrawingCacheBackgroundColor(int);
         method public void setDrawingCacheEnabled(boolean);
    @@ -25974,6 +26061,7 @@
         method public static int getChildMeasureSpec(int, int, int);
         method protected boolean getChildStaticTransformation(android.view.View, android.view.animation.Transformation);
         method public boolean getChildVisibleRect(android.view.View, android.graphics.Rect, android.graphics.Point);
    +    method public boolean getClipChildren();
         method public int getDescendantFocusability();
         method public android.view.View getFocusedChild();
         method public android.view.animation.LayoutAnimationController getLayoutAnimation();
    @@ -26135,6 +26223,7 @@
         method public android.view.ViewPropertyAnimator alphaBy(float);
         method public void cancel();
         method public long getDuration();
    +    method public android.animation.TimeInterpolator getInterpolator();
         method public long getStartDelay();
         method public android.view.ViewPropertyAnimator rotation(float);
         method public android.view.ViewPropertyAnimator rotationBy(float);
    @@ -27600,7 +27689,7 @@
         method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
         method public void onRequestFocus(android.webkit.WebView);
         method public void onShowCustomView(android.view.View, android.webkit.WebChromeClient.CustomViewCallback);
    -    method public void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback);
    +    method public deprecated void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback);
       }
     
       public static abstract interface WebChromeClient.CustomViewCallback {
    @@ -27966,11 +28055,11 @@
       public class WebViewDatabase {
         method public void clearFormData();
         method public void clearHttpAuthUsernamePassword();
    -    method public void clearUsernamePassword();
    +    method public deprecated void clearUsernamePassword();
         method public static android.webkit.WebViewDatabase getInstance(android.content.Context);
         method public boolean hasFormData();
         method public boolean hasHttpAuthUsernamePassword();
    -    method public boolean hasUsernamePassword();
    +    method public deprecated boolean hasUsernamePassword();
       }
     
       public class WebViewFragment extends android.app.Fragment {
    
    diff --git a/core/java/android/animation/Animatable.java b/core/java/android/animation/Animatable.java
    new file mode 100644
    index 0000000..f9ccb4d
    --- /dev/null
    +++ b/core/java/android/animation/Animatable.java
    
    @@ -0,0 +1,72 @@
    +/*
    + * 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.animation;
    +
    +/**
    + * This interface is implemented by animation-related classes that expose
    + * the ability to set and get duration, startDelay, and interpolators.
    + */
    +public interface Animatable {
    +
    +    /**
    +     * The amount of time, in milliseconds, to delay processing the animation
    +     * after the animation is started. The {@link #setDuration(long)} of the
    +     * animation will not begin to elapse until after the startDelay has elapsed.
    +     *
    +     * @return the number of milliseconds to delay running the animation
    +     */
    +    long getStartDelay();
    +
    +    /**
    +     * The amount of time, in milliseconds, to delay processing the animation
    +     * after the animation is started. The {@link #setDuration(long)} of the
    +     * animation will not begin to elapse until after the startDelay has elapsed.
    +
    +     * @param startDelay The amount of the delay, in milliseconds
    +     */
    +    void setStartDelay(long startDelay);
    +
    +    /**
    +     * Sets the length of the animation.
    +     *
    +     * @param duration The length of the animation, in milliseconds.
    +     */
    +    Animatable setDuration(long duration);
    +
    +    /**
    +     * Gets the duration of the animation.
    +     *
    +     * @return The length of the animation, in milliseconds.
    +     */
    +    long getDuration();
    +
    +    /**
    +     * The time interpolator used in calculating the elapsed fraction of the
    +     * animation. The interpolator determines whether the animation runs with
    +     * linear or non-linear motion, such as acceleration and deceleration.
    +     *
    +     * @param value the interpolator to be used by this animation
    +     */
    +    void setInterpolator(TimeInterpolator value);
    +
    +    /**
    +     * Returns the timing interpolator that this animation uses.
    +     *
    +     * @return The timing interpolator for this animation.
    +     */
    +    public TimeInterpolator getInterpolator();
    +}
    
    diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
    index 788765d..da97d72 100644
    --- a/core/java/android/animation/Animator.java
    +++ b/core/java/android/animation/Animator.java
    
    @@ -22,14 +22,21 @@
      * This is the superclass for classes which provide basic support for animations which can be
      * started, ended, and have <code>AnimatorListeners</code> added to them.
      */
    -public abstract class Animator implements Cloneable {
    -
    +public abstract class Animator implements Cloneable, Animatable {
     
         /**
          * The set of listeners to be sent events through the life of an animation.
          */
         ArrayList<AnimatorListener> mListeners = null;
     
    +    @Override
    +    public abstract Animator setDuration(long duration);
    +
    +    @Override
    +    public TimeInterpolator getInterpolator() {
    +        return null;
    +    }
    +
         /**
          * Starts this animation. If the animation has a nonzero startDelay, the animation will start
          * running after that delay elapses. A non-delayed animation will have its initial
    @@ -70,47 +77,6 @@
         }
     
         /**
    -     * The amount of time, in milliseconds, to delay starting the animation after
    -     * {@link #start()} is called.
    -     *
    -     * @return the number of milliseconds to delay running the animation
    -     */
    -    public abstract long getStartDelay();
    -
    -    /**
    -     * The amount of time, in milliseconds, to delay starting the animation after
    -     * {@link #start()} is called.
    -
    -     * @param startDelay The amount of the delay, in milliseconds
    -     */
    -    public abstract void setStartDelay(long startDelay);
    -
    -
    -    /**
    -     * Sets the length of the animation.
    -     *
    -     * @param duration The length of the animation, in milliseconds.
    -     */
    -    public abstract Animator setDuration(long duration);
    -
    -    /**
    -     * Gets the length of the animation.
    -     *
    -     * @return The length of the animation, in milliseconds.
    -     */
    -    public abstract long getDuration();
    -
    -    /**
    -     * The time interpolator used in calculating the elapsed fraction of this animation. The
    -     * interpolator determines whether the animation runs with linear or non-linear motion,
    -     * such as acceleration and deceleration. The default value is
    -     * {@link android.view.animation.AccelerateDecelerateInterpolator}
    -     *
    -     * @param value the interpolator to be used by this animation
    -     */
    -    public abstract void setInterpolator(TimeInterpolator value);
    -
    -    /**
          * Returns whether this Animator is currently running (having been started and gone past any
          * initial startDelay period and not yet ended).
          *
    
    diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
    index f9fa444..b48853b 100644
    --- a/core/java/android/animation/AnimatorSet.java
    +++ b/core/java/android/animation/AnimatorSet.java
    
    @@ -120,9 +120,19 @@
         // set, it is passed along to the child animations.
         private long mDuration = -1;
     
    +    // Records the interpolator for the set. Null value indicates that no interpolator
    +    // was set on this AnimatorSet, so it should not be passed down to the children.
    +    private TimeInterpolator mInterpolator = null;
    +
     
         /**
          * Sets up this AnimatorSet to play all of the supplied animations at the same time.
    +     * This is equivalent to calling {@link #play(Animator)} with the first animator in the
    +     * set and then {@link Builder#with(Animator)} with each of the other animators. Note that
    +     * an Animator with a {@link Animator#setStartDelay(long) startDelay} will not actually
    +     * start until that delay elapses, which means that if the first animator in the list
    +     * supplied to this constructor has a startDelay, none of the other animators will start
    +     * until that first animator's startDelay has elapsed.
          *
          * @param items The animations that will be started simultaneously.
          */
    @@ -230,15 +240,21 @@
     
         /**
          * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
    -     * of this AnimatorSet.
    +     * of this AnimatorSet. The default value is null, which means that no interpolator
    +     * is set on this AnimatorSet. Setting the interpolator to any non-null value
    +     * will cause that interpolator to be set on the child animations
    +     * when the set is started.
          *
          * @param interpolator the interpolator to be used by each child animation of this AnimatorSet
          */
         @Override
         public void setInterpolator(TimeInterpolator interpolator) {
    -        for (Node node : mNodes) {
    -            node.animation.setInterpolator(interpolator);
    -        }
    +        mInterpolator = interpolator;
    +    }
    +
    +    @Override
    +    public TimeInterpolator getInterpolator() {
    +        return mInterpolator;
         }
     
         /**
    @@ -460,7 +476,12 @@
                     node.animation.setDuration(mDuration);
                 }
             }
    -        // First, sort the nodes (if necessary). This will ensure that sortedNodes
    +        if (mInterpolator != null) {
    +            for (Node node : mNodes) {
    +                node.animation.setInterpolator(mInterpolator);
    +            }
    +        }
    +            // First, sort the nodes (if necessary). This will ensure that sortedNodes
             // contains the animation nodes in the correct order.
             sortNodes();
     
    
    diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
    index ea605b9..cb44264 100644
    --- a/core/java/android/animation/ValueAnimator.java
    +++ b/core/java/android/animation/ValueAnimator.java
    
    @@ -16,10 +16,8 @@
     
     package android.animation;
     
    -import android.os.Handler;
     import android.os.Looper;
    -import android.os.Message;
    -import android.os.SystemProperties;
    +import android.os.Trace;
     import android.util.AndroidRuntimeException;
     import android.view.Choreographer;
     import android.view.animation.AccelerateDecelerateInterpolator;
    @@ -48,6 +46,7 @@
      * Animation</a> developer guide.</p>
      * </div>
      */
    +@SuppressWarnings("unchecked")
     public class ValueAnimator extends Animator {
     
         /**
    @@ -340,7 +339,7 @@
                 return;
             }
             if (mValues == null || mValues.length == 0) {
    -            setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofInt("", values)});
    +            setValues(PropertyValuesHolder.ofInt("", values));
             } else {
                 PropertyValuesHolder valuesHolder = mValues[0];
                 valuesHolder.setIntValues(values);
    @@ -368,7 +367,7 @@
                 return;
             }
             if (mValues == null || mValues.length == 0) {
    -            setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofFloat("", values)});
    +            setValues(PropertyValuesHolder.ofFloat("", values));
             } else {
                 PropertyValuesHolder valuesHolder = mValues[0];
                 valuesHolder.setFloatValues(values);
    @@ -400,8 +399,7 @@
                 return;
             }
             if (mValues == null || mValues.length == 0) {
    -            setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofObject("",
    -                    (TypeEvaluator)null, values)});
    +            setValues(PropertyValuesHolder.ofObject("", null, values));
             } else {
                 PropertyValuesHolder valuesHolder = mValues[0];
                 valuesHolder.setObjectValues(values);
    @@ -423,7 +421,7 @@
             mValues = values;
             mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
             for (int i = 0; i < numValues; ++i) {
    -            PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i];
    +            PropertyValuesHolder valuesHolder = values[i];
                 mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
             }
             // New property/values/target should cause re-initialization prior to starting
    @@ -537,6 +535,7 @@
          *
          * @hide
          */
    +    @SuppressWarnings("unchecked")
         protected static class AnimationHandler implements Runnable {
             // The per-thread list of all active animations
             /** @hide */
    @@ -854,6 +853,7 @@
          *
          * @return The timing interpolator for this ValueAnimator.
          */
    +    @Override
         public TimeInterpolator getInterpolator() {
             return mInterpolator;
         }
    @@ -1024,6 +1024,8 @@
             mStarted = false;
             mStartListenersCalled = false;
             mPlayingBackwards = false;
    +        Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "animator",
    +                System.identityHashCode(this));
         }
     
         /**
    @@ -1031,6 +1033,8 @@
          * called on the UI thread.
          */
         private void startAnimation(AnimationHandler handler) {
    +        Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "animator",
    +                System.identityHashCode(this));
             initAnimation();
             handler.mAnimations.add(this);
             if (mStartDelay > 0 && mListeners != null) {
    @@ -1095,7 +1099,7 @@
                             }
                         }
                         if (mRepeatMode == REVERSE) {
    -                        mPlayingBackwards = mPlayingBackwards ? false : true;
    +                        mPlayingBackwards = !mPlayingBackwards;
                         }
                         mCurrentIteration += (int)fraction;
                         fraction = fraction % 1f;
    @@ -1252,7 +1256,7 @@
             }
         }
     
    -    private AnimationHandler getOrCreateAnimationHandler() {
    +    private static AnimationHandler getOrCreateAnimationHandler() {
             AnimationHandler handler = sAnimationHandler.get();
             if (handler == null) {
                 handler = new AnimationHandler();
    
    diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
    index c99051b..98baa0e 100644
    --- a/core/java/android/app/ActivityManagerNative.java
    +++ b/core/java/android/app/ActivityManagerNative.java
    
    @@ -1413,6 +1413,14 @@
                 return true;
             }
             
    +        case SET_USER_IS_MONKEY_TRANSACTION: {
    +            data.enforceInterface(IActivityManager.descriptor);
    +            final boolean monkey = (data.readInt() == 1);
    +            setUserIsMonkey(monkey);
    +            reply.writeNoException();
    +            return true;
    +        }
    +
             case FINISH_HEAVY_WEIGHT_APP_TRANSACTION: {
                 data.enforceInterface(IActivityManager.descriptor);
                 finishHeavyWeightApp();
    @@ -3633,7 +3641,18 @@
             reply.recycle();
             return res;
         }
    -    
    +
    +    public void setUserIsMonkey(boolean monkey) throws RemoteException {
    +        Parcel data = Parcel.obtain();
    +        Parcel reply = Parcel.obtain();
    +        data.writeInterfaceToken(IActivityManager.descriptor);
    +        data.writeInt(monkey ? 1 : 0);
    +        mRemote.transact(SET_USER_IS_MONKEY_TRANSACTION, data, reply, 0);
    +        reply.readException();
    +        data.recycle();
    +        reply.recycle();
    +    }
    +
         public void finishHeavyWeightApp() throws RemoteException {
             Parcel data = Parcel.obtain();
             Parcel reply = Parcel.obtain();
    
    diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
    index 9e3cd7e..a26b88c 100644
    --- a/core/java/android/app/ApplicationLoaders.java
    +++ b/core/java/android/app/ApplicationLoaders.java
    
    @@ -16,6 +16,7 @@
     
     package android.app;
     
    +import android.os.Trace;
     import dalvik.system.PathClassLoader;
     
     import java.util.HashMap;
    @@ -54,14 +55,19 @@
                         return loader;
                     }
         
    +                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                     PathClassLoader pathClassloader =
                         new PathClassLoader(zip, libPath, parent);
    -                
    +                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    +
                     mLoaders.put(zip, pathClassloader);
                     return pathClassloader;
                 }
     
    -            return new PathClassLoader(zip, parent);
    +            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
    +            PathClassLoader pathClassloader = new PathClassLoader(zip, parent);
    +            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    +            return pathClassloader;
             }
         }
     
    
    diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
    index fa8839a..33a2770 100644
    --- a/core/java/android/app/IActivityManager.java
    +++ b/core/java/android/app/IActivityManager.java
    
    @@ -285,7 +285,9 @@
                 int enterAnim, int exitAnim) throws RemoteException;
         
         public boolean isUserAMonkey() throws RemoteException;
    -    
    +
    +    public void setUserIsMonkey(boolean monkey) throws RemoteException;
    +
         public void finishHeavyWeightApp() throws RemoteException;
     
         public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
    @@ -635,4 +637,5 @@
         int REPORT_TOP_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+162;
         int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163;
         int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164;
    +    int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165;
     }
    
    diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
    index e0dfb25..a307a73 100644
    --- a/core/java/android/app/Instrumentation.java
    +++ b/core/java/android/app/Instrumentation.java
    
    @@ -189,6 +189,10 @@
             if (mPerfMetrics != null) {
                 results.putAll(mPerfMetrics);
             }
    +        if (mUiAutomation != null) {
    +            mUiAutomation.disconnect();
    +            mUiAutomation = null;
    +        }
             mThread.finishInstrumentation(resultCode, results);
         }
         
    @@ -1695,10 +1699,6 @@
                     startPerformanceSnapshot();
                 }
                 onStart();
    -            if (mUiAutomation != null) {
    -                mUiAutomation.disconnect();
    -                mUiAutomation = null;
    -            }
             }
         }
     
    
    diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
    index a7543a8..8d994c4 100644
    --- a/core/java/android/app/Notification.java
    +++ b/core/java/android/app/Notification.java
    
    @@ -427,22 +427,48 @@
         public String[] kind;
     
         /**
    -     * Extra key for people values (type TBD).
    -     *
    +     * Additional semantic data to be carried around with this Notification.
          * @hide
          */
    -    public static final String EXTRA_PEOPLE = "android.people";
    +    public Bundle extras = new Bundle();
    +
    +    // extras keys for Builder inputs
         /** @hide */
         public static final String EXTRA_TITLE = "android.title";
         /** @hide */
    +    public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
    +    /** @hide */
         public static final String EXTRA_TEXT = "android.text";
         /** @hide */
    -    public static final String EXTRA_SUBTEXT = "android.subtext";
    +    public static final String EXTRA_SUB_TEXT = "android.subText";
    +    /** @hide */
    +    public static final String EXTRA_INFO_TEXT = "android.infoText";
    +    /** @hide */
    +    public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
         /** @hide */
         public static final String EXTRA_SMALL_ICON = "android.icon";
    -
         /** @hide */
    -    public Bundle extras = new Bundle();
    +    public static final String EXTRA_LARGE_ICON = "android.largeIcon";
    +    /** @hide */
    +    public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
    +    /** @hide */
    +    public static final String EXTRA_PROGRESS = "android.progress";
    +    /** @hide */
    +    public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
    +    /** @hide */
    +    public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
    +    /** @hide */
    +    public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
    +    /** @hide */
    +    public static final String EXTRA_SHOW_WHEN = "android.showWhen";
    +    /** @hide from BigPictureStyle */
    +    public static final String EXTRA_PICTURE = "android.picture";
    +    /** @hide from InboxStyle */
    +    public static final String EXTRA_TEXT_LINES = "android.textLines";
    +
    +    // extras keys for other interesting pieces of information
    +    /** @hide */
    +    public static final String EXTRA_PEOPLE = "android.people";
     
         /**
          * Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
    @@ -1621,19 +1647,29 @@
                     mActions.toArray(n.actions);
                 }
     
    -            n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
    -
    -            // Store original information used in the construction of this object
    -            n.extras.putCharSequence(EXTRA_TITLE, mContentTitle);
    -            n.extras.putCharSequence(EXTRA_TEXT, mContentText);
    -            n.extras.putCharSequence(EXTRA_SUBTEXT, mSubText);
    -            n.extras.putInt(EXTRA_SMALL_ICON, mSmallIcon);
    -            //n.extras.putByteArray(EXTRA_LARGE_ICON, ...
    -
                 return n;
             }
     
             /**
    +         * Capture, in the provided bundle, semantic information used in the construction of
    +         * this Notification object.
    +         * @hide
    +         */
    +        public void addExtras(Bundle extras) {
    +            // Store original information used in the construction of this object
    +            extras.putCharSequence(EXTRA_TITLE, mContentTitle);
    +            extras.putCharSequence(EXTRA_TEXT, mContentText);
    +            extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
    +            extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo);
    +            extras.putInt(EXTRA_SMALL_ICON, mSmallIcon);
    +            extras.putInt(EXTRA_PROGRESS, mProgress);
    +            extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax);
    +            extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
    +            extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
    +            extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
    +        }
    +
    +        /**
              * @deprecated Use {@link #build()} instead.
              */
             @Deprecated
    @@ -1646,11 +1682,22 @@
              * object.
              */
             public Notification build() {
    +            final Notification n;
    +
                 if (mStyle != null) {
    -                return mStyle.build();
    +                n = mStyle.build();
                 } else {
    -                return buildUnstyled();
    +                n = buildUnstyled();
                 }
    +
    +            n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
    +
    +            addExtras(n.extras);
    +            if (mStyle != null) {
    +                mStyle.addExtras(n.extras);
    +            }
    +
    +            return n;
             }
     
             /**
    @@ -1664,7 +1711,6 @@
             }
         }
     
    -
         /**
          * An object that can apply a rich notification style to a {@link Notification.Builder}
          * object.
    @@ -1739,6 +1785,18 @@
                 return contentView;
             }
     
    +        /**
    +         * @hide
    +         */
    +        public void addExtras(Bundle extras) {
    +            if (mSummaryTextSet) {
    +                extras.putCharSequence(EXTRA_SUMMARY_TEXT, mSummaryText);
    +            }
    +            if (mBigContentTitle != null) {
    +                extras.putCharSequence(EXTRA_TITLE_BIG, mBigContentTitle);
    +            }
    +        }
    +
             public abstract Notification build();
         }
     
    @@ -1813,6 +1871,18 @@
                 return contentView;
             }
     
    +        /**
    +         * @hide
    +         */
    +        public void addExtras(Bundle extras) {
    +            super.addExtras(extras);
    +
    +            if (mBigLargeIconSet) {
    +                extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon);
    +            }
    +            extras.putParcelable(EXTRA_PICTURE, mPicture);
    +        }
    +
             @Override
             public Notification build() {
                 checkBuilder();
    @@ -1878,6 +1948,15 @@
                 return this;
             }
     
    +        /**
    +         * @hide
    +         */
    +        public void addExtras(Bundle extras) {
    +            super.addExtras(extras);
    +
    +            extras.putCharSequence(EXTRA_TEXT, mBigText);
    +        }
    +
             private RemoteViews makeBigContentView() {
                 // Remove the content text so line3 only shows if you have a summary
                 final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null);
    @@ -1964,6 +2043,15 @@
                 return this;
             }
     
    +        /**
    +         * @hide
    +         */
    +        public void addExtras(Bundle extras) {
    +            super.addExtras(extras);
    +            CharSequence[] a = new CharSequence[mTexts.size()];
    +            extras.putCharSequenceArray(EXTRA_TEXT_LINES, mTexts.toArray(a));
    +        }
    +
             private RemoteViews makeBigContentView() {
                 // Remove the content text so line3 disappears unless you have a summary
                 mBuilder.mContentText = null;
    @@ -2005,13 +2093,6 @@
                 Notification wip = mBuilder.buildUnstyled();
                 wip.bigContentView = makeBigContentView();
     
    -            StringBuilder builder = new StringBuilder();
    -            for (CharSequence str : mTexts) {
    -                builder.append(str);
    -                builder.append("\n");
    -            }
    -            wip.extras.putCharSequence(EXTRA_TEXT, builder);
    -
                 return wip;
             }
         }
    
    diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
    index d9799b6..05b79c1 100644
    --- a/core/java/android/app/UiAutomation.java
    +++ b/core/java/android/app/UiAutomation.java
    
    @@ -619,6 +619,25 @@
             return screenShot;
         }
     
    +    /**
    +     * Sets whether this UiAutomation to run in a "monkey" mode. Applications can query whether
    +     * they are executed in a "monkey" mode, i.e. run by a test framework, and avoid doing
    +     * potentially undesirable actions such as calling 911 or posting on public forums etc.
    +     *
    +     * @param enable whether to run in a "monkey" mode or not. Default is not.
    +     * @see {@link ActivityManager#isUserAMonkey()}
    +     */
    +    public void setRunAsMonkey(boolean enable) {
    +        synchronized (mLock) {
    +            throwIfNotConnectedLocked();
    +        }
    +        try {
    +            ActivityManagerNative.getDefault().setUserIsMonkey(enable);
    +        } catch (RemoteException re) {
    +            Log.e(LOG_TAG, "Error while setting run as monkey!", re);
    +        }
    +    }
    +
         private static float getDegreesForRotation(int value) {
             switch (value) {
                 case Surface.ROTATION_90: {
    
    diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
    index 33a6757..af1a6d5 100644
    --- a/core/java/android/content/pm/PackageInfo.java
    +++ b/core/java/android/content/pm/PackageInfo.java
    
    @@ -224,6 +224,9 @@
         /** @hide */
         public String restrictedAccountType;
     
    +    /** @hide */
    +    public String requiredAccountType;
    +
         public PackageInfo() {
         }
     
    @@ -266,6 +269,7 @@
             dest.writeInt(installLocation);
             dest.writeInt(requiredForAllUsers ? 1 : 0);
             dest.writeString(restrictedAccountType);
    +        dest.writeString(requiredAccountType);
         }
     
         public static final Parcelable.Creator<PackageInfo> CREATOR
    @@ -306,5 +310,6 @@
             installLocation = source.readInt();
             requiredForAllUsers = source.readInt() != 0;
             restrictedAccountType = source.readString();
    +        requiredAccountType = source.readString();
         }
     }
    
    diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
    index 5a50ec2..acb3725 100644
    --- a/core/java/android/content/pm/PackageParser.java
    +++ b/core/java/android/content/pm/PackageParser.java
    
    @@ -289,6 +289,7 @@
             pi.installLocation = p.installLocation;
             pi.requiredForAllUsers = p.mRequiredForAllUsers;
             pi.restrictedAccountType = p.mRestrictedAccountType;
    +        pi.requiredAccountType = p.mRequiredAccountType;
             pi.firstInstallTime = firstInstallTime;
             pi.lastUpdateTime = lastUpdateTime;
             if ((flags&PackageManager.GET_GIDS) != 0) {
    @@ -1816,11 +1817,18 @@
                         false)) {
                     owner.mRequiredForAllUsers = true;
                 }
    -            String accountType = sa.getString(com.android.internal.R.styleable
    -                    .AndroidManifestApplication_restrictedAccountType);
    -            if (accountType != null && accountType.length() > 0) {
    -                owner.mRestrictedAccountType = accountType;
    -            }
    +        }
    +
    +        String restrictedAccountType = sa.getString(com.android.internal.R.styleable
    +                .AndroidManifestApplication_restrictedAccountType);
    +        if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
    +            owner.mRestrictedAccountType = restrictedAccountType;
    +        }
    +
    +        String requiredAccountType = sa.getString(com.android.internal.R.styleable
    +                .AndroidManifestApplication_requiredAccountType);
    +        if (requiredAccountType != null && requiredAccountType.length() > 0) {
    +            owner.mRequiredAccountType = requiredAccountType;
             }
     
             if (sa.getBoolean(
    @@ -3339,6 +3347,9 @@
             /* The restricted account authenticator type that is used by this application */
             public String mRestrictedAccountType;
     
    +        /* The required account type without which this application will not function */
    +        public String mRequiredAccountType;
    +
             /**
              * Digest suitable for comparing whether this package's manifest is the
              * same as another.
    
    diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
    index ffefaa2..fc9e486 100644
    --- a/core/java/android/content/res/AssetManager.java
    +++ b/core/java/android/content/res/AssetManager.java
    
    @@ -17,6 +17,7 @@
     package android.content.res;
     
     import android.os.ParcelFileDescriptor;
    +import android.os.Trace;
     import android.util.Log;
     import android.util.TypedValue;
     
    @@ -602,7 +603,12 @@
          * the cookie of the added asset, or 0 on failure.
          * {@hide}
          */
    -    public native final int addAssetPath(String path);
    +    public final int addAssetPath(String path) {
    +        int res = addAssetPathNative(path);
    +        return res;
    +    }
    +
    +    private native final int addAssetPathNative(String path);
     
         /**
          * Add multiple sets of assets to the asset manager at once.  See
    
    diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
    index 9338f3d..d64bff9 100644
    --- a/core/java/android/content/res/Resources.java
    +++ b/core/java/android/content/res/Resources.java
    
    @@ -16,6 +16,7 @@
     
     package android.content.res;
     
    +import android.os.Trace;
     import com.android.internal.util.XmlUtils;
     
     import org.xmlpull.v1.XmlPullParser;
    @@ -2055,20 +2056,24 @@
                             + value.assetCookie + ": " + file);
     
                     if (file.endsWith(".xml")) {
    +                    Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
                         try {
                             XmlResourceParser rp = loadXmlResourceParser(
                                     file, id, value.assetCookie, "drawable");
                             dr = Drawable.createFromXml(this, rp);
                             rp.close();
                         } catch (Exception e) {
    +                        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
                             NotFoundException rnf = new NotFoundException(
                                 "File " + file + " from drawable resource ID #0x"
                                 + Integer.toHexString(id));
                             rnf.initCause(e);
                             throw rnf;
                         }
    +                    Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
     
                     } else {
    +                    Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
                         try {
                             InputStream is = mAssets.openNonAsset(
                                     value.assetCookie, file, AssetManager.ACCESS_STREAMING);
    @@ -2078,12 +2083,14 @@
                             is.close();
             //                System.out.println("Created stream: " + dr);
                         } catch (Exception e) {
    +                        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
                             NotFoundException rnf = new NotFoundException(
                                 "File " + file + " from drawable resource ID #0x"
                                 + Integer.toHexString(id));
                             rnf.initCause(e);
                             throw rnf;
                         }
    +                    Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
                     }
                 }
             }
    @@ -2189,18 +2196,21 @@
             String file = value.string.toString();
     
             if (file.endsWith(".xml")) {
    +            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
                 try {
                     XmlResourceParser rp = loadXmlResourceParser(
                             file, id, value.assetCookie, "colorstatelist"); 
                     csl = ColorStateList.createFromXml(this, rp);
                     rp.close();
                 } catch (Exception e) {
    +                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
                     NotFoundException rnf = new NotFoundException(
                         "File " + file + " from color state list resource ID #0x"
                         + Integer.toHexString(id));
                     rnf.initCause(e);
                     throw rnf;
                 }
    +            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
             } else {
                 throw new NotFoundException(
                         "File " + file + " from drawable resource ID #0x"
    
    diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
    index 37cbe04..30118f9 100644
    --- a/core/java/android/hardware/SensorManager.java
    +++ b/core/java/android/hardware/SensorManager.java
    
    @@ -1387,14 +1387,14 @@
          * @throws IllegalArgumentException when sensor is a trigger sensor.
          */
         public boolean cancelTriggerSensor(TriggerEventListener listener, Sensor sensor) {
    -        return cancelTriggerSensorImpl(listener, sensor);
    +        return cancelTriggerSensorImpl(listener, sensor, true);
         }
     
         /**
          * @hide
          */
         protected abstract boolean cancelTriggerSensorImpl(TriggerEventListener listener,
    -            Sensor sensor);
    +            Sensor sensor, boolean disable);
     
     
         private LegacySensorManager getLegacySensorManager() {
    
    diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
    index c6c999b..852cf4a 100644
    --- a/core/java/android/hardware/SystemSensorManager.java
    +++ b/core/java/android/hardware/SystemSensorManager.java
    
    @@ -20,6 +20,7 @@
     import android.os.Handler;
     import android.os.Looper;
     import android.os.MessageQueue;
    +import android.util.Log;
     import android.util.SparseArray;
     import android.util.SparseBooleanArray;
     import android.util.SparseIntArray;
    @@ -135,7 +136,7 @@
                     if (sensor == null) {
                         result = queue.removeAllSensors();
                     } else {
    -                    result = queue.removeSensor(sensor);
    +                    result = queue.removeSensor(sensor, true);
                     }
                     if (result && !queue.hasSensors()) {
                         mSensorListeners.remove(listener);
    @@ -170,7 +171,8 @@
     
         /** @hide */
         @Override
    -    protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
    +    protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
    +            boolean disable) {
             if (sensor != null && Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) {
                 return false;
             }
    @@ -181,7 +183,7 @@
                     if (sensor == null) {
                         result = queue.removeAllSensors();
                     } else {
    -                    result = queue.removeSensor(sensor);
    +                    result = queue.removeSensor(sensor, disable);
                     }
                     if (result && !queue.hasSensors()) {
                         mTriggerListeners.remove(listener);
    @@ -225,14 +227,17 @@
     
             public boolean addSensor(Sensor sensor, int delay) {
                 // Check if already present.
    -            if (mActiveSensors.get(sensor.getHandle())) return false;
    +            int handle = sensor.getHandle();
    +            if (mActiveSensors.get(handle)) return false;
     
    -            if (enableSensor(sensor, delay) == 0) {
    -                mActiveSensors.put(sensor.getHandle(), true);
    -                addSensorEvent(sensor);
    -                return true;
    +            // Get ready to receive events before calling enable.
    +            mActiveSensors.put(handle, true);
    +            addSensorEvent(sensor);
    +            if (enableSensor(sensor, delay) != 0) {
    +                removeSensor(sensor, false);
    +                return false;
                 }
    -            return false;
    +            return true;
             }
     
             public boolean removeAllSensors() {
    @@ -252,10 +257,10 @@
                 return true;
             }
     
    -        public boolean removeSensor(Sensor sensor) {
    +        public boolean removeSensor(Sensor sensor, boolean disable) {
                 final int handle = sensor.getHandle();
                 if (mActiveSensors.get(handle)) {
    -                disableSensor(sensor);
    +                if (disable) disableSensor(sensor);
                     mActiveSensors.put(sensor.getHandle(), false);
                     removeSensorEvent(sensor);
                     return true;
    @@ -334,6 +339,10 @@
                     long timestamp) {
                 final Sensor sensor = sHandleToSensor.get(handle);
                 SensorEvent t = mSensorsEvents.get(handle);
    +            if (t == null) {
    +                Log.e(TAG, "Error: Sensor Event is null for Sensor: " + sensor);
    +                return;
    +            }
                 // Copy from the values array.
                 System.arraycopy(values, 0, t.values, 0, t.values.length);
                 t.timestamp = timestamp;
    @@ -390,14 +399,19 @@
                     long timestamp) {
                 final Sensor sensor = sHandleToSensor.get(handle);
                 TriggerEvent t = mTriggerEvents.get(handle);
    +            if (t == null) {
    +                Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
    +                return;
    +            }
     
                 // Copy from the values array.
                 System.arraycopy(values, 0, t.values, 0, t.values.length);
                 t.timestamp = timestamp;
                 t.sensor = sensor;
     
    -            // A trigger sensor should be auto disabled.
    -            mManager.cancelTriggerSensorImpl(mListener, sensor);
    +            // A trigger sensor is auto disabled. So just clean up and don't call native
    +            // disable.
    +            mManager.cancelTriggerSensorImpl(mListener, sensor, false);
     
                 mListener.onTrigger(t);
             }
    
    diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
    index cc3c5f7..1d051dd 100644
    --- a/core/java/android/net/RouteInfo.java
    +++ b/core/java/android/net/RouteInfo.java
    
    @@ -60,6 +60,7 @@
     
         private final boolean mIsDefault;
         private final boolean mIsHost;
    +    private final boolean mHasGateway;
     
         /**
          * Constructs a RouteInfo object.
    @@ -97,6 +98,8 @@
                     gateway = Inet6Address.ANY;
                 }
             }
    +        mHasGateway = (!gateway.isAnyLocalAddress());
    +
             mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
                     destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
             mGateway = gateway;
    @@ -171,6 +174,10 @@
             return mIsHost;
         }
     
    +    public boolean hasGateway() {
    +        return mHasGateway;
    +    }
    +
         public String toString() {
             String val = "";
             if (mDestination != null) val = mDestination.toString();
    
    diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
    index 607def7..617f490 100644
    --- a/core/java/android/os/Trace.java
    +++ b/core/java/android/os/Trace.java
    
    @@ -63,6 +63,8 @@
         public static final long TRACE_TAG_HAL = 1L << 11;
         /** @hide */
         public static final long TRACE_TAG_APP = 1L << 12;
    +    /** @hide */
    +    public static final long TRACE_TAG_RESOURCES = 1L << 13;
     
         private static final long TRACE_TAG_NOT_READY = 1L << 63;
         private static final int MAX_SECTION_NAME_LEN = 127;
    @@ -74,6 +76,8 @@
         private static native void nativeTraceCounter(long tag, String name, int value);
         private static native void nativeTraceBegin(long tag, String name);
         private static native void nativeTraceEnd(long tag);
    +    private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
    +    private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
         private static native void nativeSetAppTracingAllowed(boolean allowed);
     
         static {
    @@ -195,6 +199,42 @@
         }
     
         /**
    +     * Writes a trace message to indicate that a given section of code has
    +     * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same
    +     * tag. Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)},
    +     * asynchronous events do not need to be nested. The name and cookie used to
    +     * begin an event must be used to end it.
    +     *
    +     * @param traceTag The trace tag.
    +     * @param methodName The method name to appear in the trace.
    +     * @param cookie Unique identifier for distinguishing simultaneous events
    +     *
    +     * @hide
    +     */
    +    public static void asyncTraceBegin(long traceTag, String methodName, int cookie) {
    +        if (isTagEnabled(traceTag)) {
    +            nativeAsyncTraceBegin(traceTag, methodName, cookie);
    +        }
    +    }
    +
    +    /**
    +     * Writes a trace message to indicate that the current method has ended.
    +     * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)}
    +     * using the same tag, name and cookie.
    +     *
    +     * @param traceTag The trace tag.
    +     * @param methodName The method name to appear in the trace.
    +     * @param cookie Unique identifier for distinguishing simultaneous events
    +     *
    +     * @hide
    +     */
    +    public static void asyncTraceEnd(long traceTag, String methodName, int cookie) {
    +        if (isTagEnabled(traceTag)) {
    +            nativeAsyncTraceEnd(traceTag, methodName, cookie);
    +        }
    +    }
    +
    +    /**
          * Writes a trace message to indicate that a given section of code has begun. This call must
          * be followed by a corresponding call to {@link #endSection()} on the same thread.
          *
    
    diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
    index b9b8f08..e580e2b 100644
    --- a/core/java/android/os/UserManager.java
    +++ b/core/java/android/os/UserManager.java
    
    @@ -110,7 +110,6 @@
          */
         public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
     
    -
         /**
          * Key for user restrictions. Specifies if a user is disallowed from transferring files over
          * USB. The default value is <code>false</code>.
    @@ -121,6 +120,26 @@
          */
         public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
     
    +    /**
    +     * Key for user restrictions. Specifies if a user is disallowed from configuring user
    +     * credentials. The default value is <code>false</code>.
    +     * <p/>
    +     * Type: Boolean
    +     * @see #setUserRestrictions(Bundle)
    +     * @see #getUserRestrictions()
    +     */
    +    public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
    +
    +    /**
    +     * Key for user restrictions. Specifies if a user is disallowed from removing users.
    +     * The default value is <code>false</code>.
    +     * <p/>
    +     * Type: Boolean
    +     * @see #setUserRestrictions(Bundle)
    +     * @see #getUserRestrictions()
    +     */
    +    public static final String DISALLOW_REMOVE_USER = "no_remove_user";
    +
         private static UserManager sInstance = null;
     
         public synchronized static UserManager get(Context context) {
    @@ -179,16 +198,15 @@
         }
     
         /**
    -     * Used to check if the user making this call is a restricted user. Restricted users may have
    -     * application restrictions imposed on them. All apps should default to the most restrictive
    -     * version, unless they have specific restrictions available through a call to
    -     * {@link Context#getApplicationRestrictions()}.
    +     * Used to check if the user making this call is linked to another user. Linked users may have
    +     * a reduced number of available apps, app restrictions and account restrictions.
    +     * @return whether the user making this call is a linked user
          */
    -    public boolean isUserRestricted() {
    +    public boolean isLinkedUser() {
             try {
                 return mService.isRestricted();
             } catch (RemoteException re) {
    -            Log.w(TAG, "Could not check if user restricted ", re);
    +            Log.w(TAG, "Could not check if user is limited ", re);
                 return false;
             }
         }
    
    diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
    index e1cc90e..3d75dc8 100644
    --- a/core/java/android/security/IKeystoreService.java
    +++ b/core/java/android/security/IKeystoreService.java
    
    @@ -78,7 +78,7 @@
                     return _result;
                 }
     
    -            public int insert(String name, byte[] item, int uid) throws RemoteException {
    +            public int insert(String name, byte[] item, int uid, int flags) throws RemoteException {
                     Parcel _data = Parcel.obtain();
                     Parcel _reply = Parcel.obtain();
                     int _result;
    @@ -87,6 +87,7 @@
                         _data.writeString(name);
                         _data.writeByteArray(item);
                         _data.writeInt(uid);
    +                    _data.writeInt(flags);
                         mRemote.transact(Stub.TRANSACTION_insert, _data, _reply, 0);
                         _reply.readException();
                         _result = _reply.readInt();
    @@ -243,7 +244,7 @@
                     return _result;
                 }
     
    -            public int generate(String name, int uid) throws RemoteException {
    +            public int generate(String name, int uid, int flags) throws RemoteException {
                     Parcel _data = Parcel.obtain();
                     Parcel _reply = Parcel.obtain();
                     int _result;
    @@ -251,6 +252,7 @@
                         _data.writeInterfaceToken(DESCRIPTOR);
                         _data.writeString(name);
                         _data.writeInt(uid);
    +                    _data.writeInt(flags);
                         mRemote.transact(Stub.TRANSACTION_generate, _data, _reply, 0);
                         _reply.readException();
                         _result = _reply.readInt();
    @@ -261,7 +263,8 @@
                     return _result;
                 }
     
    -            public int import_key(String name, byte[] data, int uid) throws RemoteException {
    +            public int import_key(String name, byte[] data, int uid, int flags)
    +                    throws RemoteException {
                     Parcel _data = Parcel.obtain();
                     Parcel _reply = Parcel.obtain();
                     int _result;
    @@ -270,6 +273,7 @@
                         _data.writeString(name);
                         _data.writeByteArray(data);
                         _data.writeInt(uid);
    +                    _data.writeInt(flags);
                         mRemote.transact(Stub.TRANSACTION_import, _data, _reply, 0);
                         _reply.readException();
                         _result = _reply.readInt();
    @@ -538,7 +542,7 @@
     
         public byte[] get(String name) throws RemoteException;
     
    -    public int insert(String name, byte[] item, int uid) throws RemoteException;
    +    public int insert(String name, byte[] item, int uid, int flags) throws RemoteException;
     
         public int del(String name, int uid) throws RemoteException;
     
    @@ -556,9 +560,9 @@
     
         public int zero() throws RemoteException;
     
    -    public int generate(String name, int uid) throws RemoteException;
    +    public int generate(String name, int uid, int flags) throws RemoteException;
     
    -    public int import_key(String name, byte[] data, int uid) throws RemoteException;
    +    public int import_key(String name, byte[] data, int uid, int flags) throws RemoteException;
     
         public byte[] sign(String name, byte[] data) throws RemoteException;
     
    
    diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
    index 85695fc..aa43bad 100644
    --- a/core/java/android/view/LayoutInflater.java
    +++ b/core/java/android/view/LayoutInflater.java
    
    @@ -654,7 +654,7 @@
     
         /**
          * Version of {@link #onCreateView(String, AttributeSet)} that also
    -     * takes the future parent of the view being constructure.  The default
    +     * takes the future parent of the view being constructed.  The default
          * implementation simply calls {@link #onCreateView(String, AttributeSet)}.
          *
          * @param parent The future parent of the returned view.  <em>Note that
    
    diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
    index 5d0f523..14fa9cb 100644
    --- a/core/java/android/view/SurfaceView.java
    +++ b/core/java/android/view/SurfaceView.java
    
    @@ -480,6 +480,7 @@
                     if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
                         mLayout.flags |= WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
                     }
    +                mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
     
                     if (mWindow == null) {
                         Display display = getDisplay();
    
    diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
    index 7c82f7e..4fb2431 100644
    --- a/core/java/android/view/View.java
    +++ b/core/java/android/view/View.java
    
    @@ -2758,6 +2758,11 @@
     
         TransformationInfo mTransformationInfo;
     
    +    /**
    +     * Current clip bounds. to which all drawing of this view are constrained.
    +     */
    +    private Rect mClipBounds = null;
    +
         private boolean mLastIsOpaque;
     
         /**
    @@ -10103,7 +10108,7 @@
         /**
          * Offset this view's horizontal location by the specified amount of pixels.
          *
    -     * @param offset the numer of pixels to offset the view by
    +     * @param offset the number of pixels to offset the view by
          */
         public void offsetLeftAndRight(int offset) {
             if (offset != 0) {
    @@ -13374,6 +13379,33 @@
         }
     
         /**
    +     * Sets a rectangular area on this view to which the view will be clipped
    +     * it is drawn. Setting the value to null will remove the clip bounds
    +     * and the view will draw normally, using its full bounds.
    +     *
    +     * @param clipBounds The rectangular area, in the local coordinates of
    +     * this view, to which future drawing operations will be clipped.
    +     */
    +    public void setClipBounds(Rect clipBounds) {
    +        mClipBounds = clipBounds;
    +        if (clipBounds != null) {
    +            invalidate(clipBounds);
    +        } else {
    +            invalidate();
    +        }
    +    }
    +
    +    /**
    +     * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}.
    +     *
    +     * @return A copy of the current clip bounds if clip bounds are set,
    +     * otherwise null.
    +     */
    +    public Rect getClipBounds() {
    +        return (mClipBounds != null) ? new Rect(mClipBounds) : null;
    +    }
    +
    +    /**
          * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common
          * case of an active Animation being run on the view.
          */
    @@ -13849,6 +13881,9 @@
          * @param canvas The Canvas to which the View is rendered.
          */
         public void draw(Canvas canvas) {
    +        if (mClipBounds != null) {
    +            canvas.clipRect(mClipBounds);
    +        }
             final int privateFlags = mPrivateFlags;
             final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
                     (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
    
    diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
    index 311d1d0..bf502dd 100644
    --- a/core/java/android/view/ViewGroup.java
    +++ b/core/java/android/view/ViewGroup.java
    
    @@ -1464,10 +1464,13 @@
                 final float y = event.getY();
                 final int childrenCount = mChildrenCount;
                 if (childrenCount != 0) {
    +                final boolean customChildOrder = isChildrenDrawingOrderEnabled();
                     final View[] children = mChildren;
                     HoverTarget lastHoverTarget = null;
                     for (int i = childrenCount - 1; i >= 0; i--) {
    -                    final View child = children[i];
    +                    final int childIndex = customChildOrder
    +                            ? getChildDrawingOrder(childrenCount, i) : i;
    +                    final View child = children[childIndex];
                         if (!canViewReceivePointerEvents(child)
                                 || !isTransformedTouchPointInView(x, y, child, null)) {
                             continue;
    @@ -3080,6 +3083,18 @@
         }
     
         /**
    +     * Returns whether ths group's children are clipped to their bounds before drawing.
    +     * The default value is true.
    +     * @see #setClipChildren(boolean)
    +     *
    +     * @return True if the group's children will be clipped to their bounds,
    +     * false otherwise.
    +     */
    +    public boolean getClipChildren() {
    +        return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
    +    }
    +
    +    /**
          * By default, children are clipped to their bounds before drawing. This
          * allows view groups to override this behavior for animations, etc.
          *
    @@ -4525,7 +4540,7 @@
          */
         @Override
         public final void layout(int l, int t, int r, int b) {
    -        if (mTransition == null || !mTransition.isChangingLayout()) {
    +        if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
                 if (mTransition != null) {
                     mTransition.layoutChange(this);
                 }
    
    diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
    index 22f98b7..98df064 100644
    --- a/core/java/android/view/ViewPropertyAnimator.java
    +++ b/core/java/android/view/ViewPropertyAnimator.java
    
    @@ -16,6 +16,7 @@
     
     package android.view;
     
    +import android.animation.Animatable;
     import android.animation.Animator;
     import android.animation.ValueAnimator;
     import android.animation.TimeInterpolator;
    @@ -323,6 +324,15 @@
         }
     
         /**
    +     * Returns the timing interpolator that this animation uses.
    +     *
    +     * @return The timing interpolator for this animation.
    +     */
    +    public TimeInterpolator getInterpolator() {
    +        return null;
    +    }
    +
    +    /**
          * Sets a listener for events in the underlying Animators that run the property
          * animations.
          *
    
    diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
    index c1db4c6..f03c077 100644
    --- a/core/java/android/view/ViewRootImpl.java
    +++ b/core/java/android/view/ViewRootImpl.java
    
    @@ -1727,7 +1727,7 @@
             if (didLayout) {
                 performLayout(lp, desiredWindowWidth, desiredWindowHeight);
     
    -            // By this point all views have been sized and positionned
    +            // By this point all views have been sized and positioned
                 // We can compute the transparent area
     
                 if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
    @@ -1745,6 +1745,7 @@
     
                     if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
                         mPreviousTransparentRegion.set(mTransparentRegion);
    +                    mFullRedrawNeeded = true;
                         // reconfigure window manager
                         try {
                             mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
    @@ -2592,12 +2593,12 @@
                 // requestChildRectangleOnScreen() call (in which case 'rectangle'
                 // is non-null and we just want to scroll to whatever that
                 // rectangle is).
    -            View focus = mView.findFocus();
    +            final View focus = mView.findFocus();
                 if (focus == null) {
                     return false;
                 }
                 View lastScrolledFocus = (mLastScrolledFocus != null) ? mLastScrolledFocus.get() : null;
    -            if (lastScrolledFocus != null && focus != lastScrolledFocus) {
    +            if (focus != lastScrolledFocus) {
                     // If the focus has changed, then ignore any requests to scroll
                     // to a rectangle; first we want to make sure the entire focus
                     // view is visible.
    @@ -2612,7 +2613,7 @@
                     // as they are.
                     if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
                             + mScrollY + " vi=" + vi.toShortString());
    -            } else if (focus != null) {
    +            } else {
                     // We need to determine if the currently focused view is
                     // within the visible part of the window and, if not, apply
                     // a pan so it can be seen.
    @@ -4922,7 +4923,7 @@
         public void handleDispatchDoneAnimating() {
             if (mWindowsAnimating) {
                 mWindowsAnimating = false;
    -            if (!mDirty.isEmpty() || mIsAnimating)  {
    +            if (!mDirty.isEmpty() || mIsAnimating || mFullRedrawNeeded)  {
                     scheduleTraversals();
                 }
             }
    
    diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
    index 96ef0b4..48630a4 100644
    --- a/core/java/android/view/WindowManager.java
    +++ b/core/java/android/view/WindowManager.java
    
    @@ -1012,6 +1012,12 @@
             public static final int PRIVATE_FLAG_FORCE_SHOW_NAV_BAR = 0x00000020;
     
             /**
    +         * Never animate position changes of the window.
    +         *
    +         * {@hide} */
    +        public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
    +
    +        /**
              * Control flags that are private to the platform.
              * @hide
              */
    
    diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
    index a326da2..312af71 100644
    --- a/core/java/android/webkit/CallbackProxy.java
    +++ b/core/java/android/webkit/CallbackProxy.java
    
    @@ -17,10 +17,8 @@
     package android.webkit;
     
     import android.app.Activity;
    -import android.app.AlertDialog;
     import android.content.ActivityNotFoundException;
     import android.content.Context;
    -import android.content.DialogInterface;
     import android.content.Intent;
     import android.graphics.Bitmap;
     import android.net.Uri;
    @@ -33,10 +31,6 @@
     import android.provider.Browser;
     import android.util.Log;
     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;
     
     import java.net.MalformedURLException;
    @@ -92,10 +86,7 @@
         private static final int CREATE_WINDOW                        = 109;
         private static final int CLOSE_WINDOW                         = 110;
         private static final int SAVE_PASSWORD                        = 111;
    -    private static final int JS_ALERT                             = 112;
    -    private static final int JS_CONFIRM                           = 113;
    -    private static final int JS_PROMPT                            = 114;
    -    private static final int JS_UNLOAD                            = 115;
    +    private static final int JS_DIALOG                            = 112;
         private static final int ASYNC_KEYEVENTS                      = 116;
         private static final int DOWNLOAD_FILE                        = 118;
         private static final int REPORT_ERROR                         = 119;
    @@ -566,188 +557,12 @@
                     }
                     break;
     
    -            case JS_ALERT:
    +            case JS_DIALOG:
                     if (mWebChromeClient != null) {
                         final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
    -                    final JsResult res = receiver.mJsResult;
    -                    String message = msg.getData().getString("message");
    -                    String url = msg.getData().getString("url");
    -                    if (!mWebChromeClient.onJsAlert(mWebView.getWebView(), url, message,
    -                            res)) {
    -                        if (!canShowAlertDialog()) {
    -                            res.cancel();
    -                            receiver.setReady();
    -                            break;
    -                        }
    -                        new AlertDialog.Builder(mContext)
    -                                .setTitle(getJsDialogTitle(url))
    -                                .setMessage(message)
    -                                .setPositiveButton(R.string.ok,
    -                                        new DialogInterface.OnClickListener() {
    -                                            public void onClick(
    -                                                    DialogInterface dialog,
    -                                                    int which) {
    -                                                res.confirm();
    -                                            }
    -                                        })
    -                                .setOnCancelListener(
    -                                        new DialogInterface.OnCancelListener() {
    -                                            public void onCancel(
    -                                                    DialogInterface dialog) {
    -                                                res.cancel();
    -                                            }
    -                                        })
    -                                .show();
    -                    }
    -                    receiver.setReady();
    -                }
    -                break;
    -
    -            case JS_CONFIRM:
    -                if (mWebChromeClient != null) {
    -                    final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
    -                    final JsResult res = receiver.mJsResult;
    -                    String message = msg.getData().getString("message");
    -                    String url = msg.getData().getString("url");
    -                    if (!mWebChromeClient.onJsConfirm(mWebView.getWebView(), url, message,
    -                            res)) {
    -                        if (!canShowAlertDialog()) {
    -                            res.cancel();
    -                            receiver.setReady();
    -                            break;
    -                        }
    -                        new AlertDialog.Builder(mContext)
    -                                .setTitle(getJsDialogTitle(url))
    -                                .setMessage(message)
    -                                .setPositiveButton(R.string.ok,
    -                                        new DialogInterface.OnClickListener() {
    -                                            public void onClick(
    -                                                    DialogInterface dialog,
    -                                                    int which) {
    -                                                res.confirm();
    -                                            }})
    -                                .setNegativeButton(R.string.cancel,
    -                                        new DialogInterface.OnClickListener() {
    -                                            public void onClick(
    -                                                    DialogInterface dialog,
    -                                                    int which) {
    -                                                res.cancel();
    -                                            }})
    -                                .setOnCancelListener(
    -                                        new DialogInterface.OnCancelListener() {
    -                                            public void onCancel(
    -                                                    DialogInterface dialog) {
    -                                                res.cancel();
    -                                            }
    -                                        })
    -                                .show();
    -                    }
    -                    // Tell the JsResult that it is ready for client
    -                    // interaction.
    -                    receiver.setReady();
    -                }
    -                break;
    -
    -            case JS_PROMPT:
    -                if (mWebChromeClient != null) {
    -                    final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
    -                    final JsPromptResult res = receiver.mJsResult;
    -                    String message = msg.getData().getString("message");
    -                    String defaultVal = msg.getData().getString("default");
    -                    String url = msg.getData().getString("url");
    -                    if (!mWebChromeClient.onJsPrompt(mWebView.getWebView(), url, message,
    -                                defaultVal, res)) {
    -                        if (!canShowAlertDialog()) {
    -                            res.cancel();
    -                            receiver.setReady();
    -                            break;
    -                        }
    -                        final LayoutInflater factory = LayoutInflater
    -                                .from(mContext);
    -                        final View view = factory.inflate(R.layout.js_prompt,
    -                                null);
    -                        final EditText v = (EditText) view
    -                                .findViewById(R.id.value);
    -                        v.setText(defaultVal);
    -                        ((TextView) view.findViewById(R.id.message))
    -                                .setText(message);
    -                        new AlertDialog.Builder(mContext)
    -                                .setTitle(getJsDialogTitle(url))
    -                                .setView(view)
    -                                .setPositiveButton(R.string.ok,
    -                                        new DialogInterface.OnClickListener() {
    -                                            public void onClick(
    -                                                    DialogInterface dialog,
    -                                                    int whichButton) {
    -                                                res.confirm(v.getText()
    -                                                        .toString());
    -                                            }
    -                                        })
    -                                .setNegativeButton(R.string.cancel,
    -                                        new DialogInterface.OnClickListener() {
    -                                            public void onClick(
    -                                                    DialogInterface dialog,
    -                                                    int whichButton) {
    -                                                res.cancel();
    -                                            }
    -                                        })
    -                                .setOnCancelListener(
    -                                        new DialogInterface.OnCancelListener() {
    -                                            public void onCancel(
    -                                                    DialogInterface dialog) {
    -                                                res.cancel();
    -                                            }
    -                                        })
    -                                .show();
    -                    }
    -                    // Tell the JsResult that it is ready for client
    -                    // interaction.
    -                    receiver.setReady();
    -                }
    -                break;
    -
    -            case JS_UNLOAD:
    -                if (mWebChromeClient != null) {
    -                    final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
    -                    final JsResult res = receiver.mJsResult;
    -                    String message = msg.getData().getString("message");
    -                    String url = msg.getData().getString("url");
    -                    if (!mWebChromeClient.onJsBeforeUnload(mWebView.getWebView(), url,
    -                            message, res)) {
    -                        if (!canShowAlertDialog()) {
    -                            res.cancel();
    -                            receiver.setReady();
    -                            break;
    -                        }
    -                        final String m = mContext.getString(
    -                                R.string.js_dialog_before_unload, message);
    -                        new AlertDialog.Builder(mContext)
    -                                .setMessage(m)
    -                                .setPositiveButton(R.string.ok,
    -                                        new DialogInterface.OnClickListener() {
    -                                            public void onClick(
    -                                                    DialogInterface dialog,
    -                                                    int which) {
    -                                                res.confirm();
    -                                            }
    -                                        })
    -                                .setNegativeButton(R.string.cancel,
    -                                        new DialogInterface.OnClickListener() {
    -                                            public void onClick(
    -                                                    DialogInterface dialog,
    -                                                    int which) {
    -                                                res.cancel();
    -                                            }
    -                                        })
    -                                .setOnCancelListener(
    -                                        new DialogInterface.OnCancelListener() {
    -                                            @Override
    -                                            public void onCancel(
    -                                                    DialogInterface dialog) {
    -                                                res.cancel();
    -                                            }
    -                                        })
    -                                .show();
    +                    JsDialogHelper helper = new JsDialogHelper(receiver.mJsResult, msg);
    +                    if (!helper.invokeCallback(mWebChromeClient, mWebView.getWebView())) {
    +                        helper.showDialog(mContext);
                         }
                         receiver.setReady();
                     }
    @@ -757,7 +572,7 @@
                     if(mWebChromeClient != null) {
                         final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
                         final JsResult res = receiver.mJsResult;
    -                    if(mWebChromeClient.onJsTimeout()) {
    +                    if (mWebChromeClient.onJsTimeout()) {
                             res.confirm();
                         } else {
                             res.cancel();
    @@ -895,24 +710,6 @@
             sendMessage(obtainMessage(SWITCH_OUT_HISTORY));
         }
     
    -    private String getJsDialogTitle(String url) {
    -        String title = url;
    -        if (URLUtil.isDataUrl(url)) {
    -            // For data: urls, we just display 'JavaScript' similar to Safari.
    -            title = mContext.getString(R.string.js_dialog_title_default);
    -        } else {
    -            try {
    -                URL aUrl = new URL(url);
    -                // For example: "The page at 'http://www.mit.edu' says:"
    -                title = mContext.getString(R.string.js_dialog_title,
    -                        aUrl.getProtocol() + "://" + aUrl.getHost());
    -            } catch (MalformedURLException ex) {
    -                // do nothing. just use the url as the title
    -            }
    -        }
    -        return title;
    -    }
    -
         //--------------------------------------------------------------------------
         // WebViewClient functions.
         // NOTE: shouldOverrideKeyEvent is never called from the WebCore thread so
    @@ -1332,9 +1129,10 @@
                 return;
             }
             JsResultReceiver result = new JsResultReceiver();
    -        Message alert = obtainMessage(JS_ALERT, result);
    +        Message alert = obtainMessage(JS_DIALOG, result);
             alert.getData().putString("message", message);
             alert.getData().putString("url", url);
    +        alert.getData().putInt("type", JsDialogHelper.ALERT);
             sendMessageToUiThreadSync(alert);
         }
     
    @@ -1345,9 +1143,10 @@
                 return false;
             }
             JsResultReceiver result = new JsResultReceiver();
    -        Message confirm = obtainMessage(JS_CONFIRM, result);
    +        Message confirm = obtainMessage(JS_DIALOG, result);
             confirm.getData().putString("message", message);
             confirm.getData().putString("url", url);
    +        confirm.getData().putInt("type", JsDialogHelper.CONFIRM);
             sendMessageToUiThreadSync(confirm);
             return result.mJsResult.getResult();
         }
    @@ -1359,10 +1158,11 @@
                 return null;
             }
             JsResultReceiver result = new JsResultReceiver();
    -        Message prompt = obtainMessage(JS_PROMPT, result);
    +        Message prompt = obtainMessage(JS_DIALOG, result);
             prompt.getData().putString("message", message);
             prompt.getData().putString("default", defaultValue);
             prompt.getData().putString("url", url);
    +        prompt.getData().putInt("type", JsDialogHelper.PROMPT);
             sendMessageToUiThreadSync(prompt);
             return result.mJsResult.getStringResult();
         }
    @@ -1374,10 +1174,11 @@
                 return true;
             }
             JsResultReceiver result = new JsResultReceiver();
    -        Message confirm = obtainMessage(JS_UNLOAD, result);
    -        confirm.getData().putString("message", message);
    -        confirm.getData().putString("url", url);
    -        sendMessageToUiThreadSync(confirm);
    +        Message unload = obtainMessage(JS_DIALOG, result);
    +        unload.getData().putString("message", message);
    +        unload.getData().putString("url", url);
    +        unload.getData().putInt("type", JsDialogHelper.UNLOAD);
    +        sendMessageToUiThreadSync(unload);
             return result.mJsResult.getResult();
         }
     
    @@ -1595,16 +1396,6 @@
             sendMessage(msg);
         }
     
    -    boolean canShowAlertDialog() {
    -        // We can only display the alert dialog if mContext is
    -        // an Activity context.
    -        // FIXME: Should we display dialogs if mContext does
    -        // not have the window focus (e.g. if the user is viewing
    -        // another Activity when the alert should be displayed?
    -        // See bug 3166409
    -        return mContext instanceof Activity;
    -    }
    -
         private synchronized void sendMessageToUiThreadSync(Message msg) {
             sendMessage(msg);
             WebCoreThreadWatchdog.pause();
    
    diff --git a/core/java/android/webkit/JsDialogHelper.java b/core/java/android/webkit/JsDialogHelper.java
    new file mode 100644
    index 0000000..bb0339e
    --- /dev/null
    +++ b/core/java/android/webkit/JsDialogHelper.java
    
    @@ -0,0 +1,185 @@
    +/*
    + * 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.webkit;
    +
    +import android.app.Activity;
    +import android.app.AlertDialog;
    +import android.content.Context;
    +import android.content.DialogInterface;
    +import android.os.Message;
    +import android.util.Log;
    +import android.view.LayoutInflater;
    +import android.view.View;
    +import android.widget.EditText;
    +import android.widget.TextView;
    +
    +import java.net.MalformedURLException;
    +import java.net.URL;
    +
    +/**
    + * Helper class to create JavaScript dialogs. It is used by
    + * different WebView implementations.
    + *
    + * @hide Helper class for internal use
    + */
    +public class JsDialogHelper {
    +
    +    private static final String TAG = "JsDialogHelper";
    +
    +    // Dialog types
    +    public static final int ALERT   = 1;
    +    public static final int CONFIRM = 2;
    +    public static final int PROMPT  = 3;
    +    public static final int UNLOAD  = 4;
    +
    +    private final String mDefaultValue;
    +    private final JsPromptResult mResult;
    +    private final String mMessage;
    +    private final int mType;
    +    private final String mUrl;
    +
    +    public JsDialogHelper(JsPromptResult result, int type, String defaultValue, String message,
    +            String url) {
    +        mResult = result;
    +        mDefaultValue = defaultValue;
    +        mMessage = message;
    +        mType = type;
    +        mUrl = url;
    +    }
    +
    +    public JsDialogHelper(JsPromptResult result, Message msg) {
    +        mResult = result;
    +        mDefaultValue = msg.getData().getString("default");
    +        mMessage = msg.getData().getString("message");
    +        mType = msg.getData().getInt("type");
    +        mUrl = msg.getData().getString("url");
    +    }
    +
    +    public boolean invokeCallback(WebChromeClient client, WebView webView) {
    +        switch (mType) {
    +            case ALERT:
    +                return client.onJsAlert(webView, mUrl, mMessage, mResult);
    +            case CONFIRM:
    +                return client.onJsConfirm(webView, mUrl, mMessage, mResult);
    +            case UNLOAD:
    +                return client.onJsBeforeUnload(webView, mUrl, mMessage, mResult);
    +            case PROMPT:
    +                return client.onJsPrompt(webView, mUrl, mMessage, mDefaultValue, mResult);
    +            default:
    +                throw new IllegalArgumentException("Unexpected type: " + mType);
    +        }
    +    }
    +
    +    public void showDialog(Context context) {
    +        if (!canShowAlertDialog(context)) {
    +            Log.w(TAG, "Cannot create a dialog, the WebView context is not an Activity");
    +            mResult.cancel();
    +            return;
    +        }
    +
    +        String title, displayMessage;
    +        int positiveTextId, negativeTextId;
    +        if (mType == UNLOAD) {
    +            title = context.getString(com.android.internal.R.string.js_dialog_before_unload_title);
    +            displayMessage = context.getString(
    +                    com.android.internal.R.string.js_dialog_before_unload, mMessage);
    +            positiveTextId = com.android.internal.R.string.js_dialog_before_unload_positive_button;
    +            negativeTextId = com.android.internal.R.string.js_dialog_before_unload_negative_button;
    +        } else {
    +            title = getJsDialogTitle(context);
    +            displayMessage = mMessage;
    +            positiveTextId = com.android.internal.R.string.ok;
    +            negativeTextId = com.android.internal.R.string.cancel;
    +        }
    +        AlertDialog.Builder builder = new AlertDialog.Builder(context);
    +        builder.setTitle(title);
    +        builder.setOnCancelListener(new CancelListener());
    +        if (mType != PROMPT) {
    +            builder.setMessage(displayMessage);
    +            builder.setPositiveButton(positiveTextId, new PositiveListener(null));
    +        } else {
    +            final View view = LayoutInflater.from(context).inflate(
    +                    com.android.internal.R.layout.js_prompt, null);
    +            EditText edit = ((EditText) view.findViewById(com.android.internal.R.id.value));
    +            edit.setText(mDefaultValue);
    +            builder.setPositiveButton(positiveTextId, new PositiveListener(edit));
    +            ((TextView) view.findViewById(com.android.internal.R.id.message)).setText(mMessage);
    +            builder.setView(view);
    +        }
    +        if (mType != ALERT) {
    +            builder.setNegativeButton(negativeTextId, new CancelListener());
    +        }
    +        builder.show();
    +    }
    +
    +    private class CancelListener implements DialogInterface.OnCancelListener,
    +            DialogInterface.OnClickListener {
    +        @Override
    +        public void onCancel(DialogInterface dialog) {
    +            mResult.cancel();
    +        }
    +        @Override
    +        public void onClick(DialogInterface dialog, int which) {
    +            mResult.cancel();
    +        }
    +    }
    +
    +    private class PositiveListener implements DialogInterface.OnClickListener {
    +        private final EditText mEdit;
    +
    +        public PositiveListener(EditText edit) {
    +            mEdit = edit;
    +        }
    +
    +        @Override
    +        public void onClick(DialogInterface dialog, int which) {
    +            if (mEdit == null) {
    +                mResult.confirm();
    +            } else {
    +                mResult.confirm(mEdit.getText().toString());
    +            }
    +        }
    +    }
    +
    +    private String getJsDialogTitle(Context context) {
    +        String title = mUrl;
    +        if (URLUtil.isDataUrl(mUrl)) {
    +            // For data: urls, we just display 'JavaScript' similar to Chrome.
    +            title = context.getString(com.android.internal.R.string.js_dialog_title_default);
    +        } else {
    +            try {
    +                URL alertUrl = new URL(mUrl);
    +                // For example: "The page at 'http://www.mit.edu' says:"
    +                title = context.getString(com.android.internal.R.string.js_dialog_title,
    +                        alertUrl.getProtocol() + "://" + alertUrl.getHost());
    +            } catch (MalformedURLException ex) {
    +                // do nothing. just use the url as the title
    +            }
    +        }
    +        return title;
    +    }
    +
    +    private static boolean canShowAlertDialog(Context context) {
    +        // We can only display the alert dialog if mContext is
    +        // an Activity context.
    +        // FIXME: Should we display dialogs if mContext does
    +        // not have the window focus (e.g. if the user is viewing
    +        // another Activity when the alert should be displayed) ?
    +        // See bug 3166409
    +        return context instanceof Activity;
    +    }
    +}
    
    diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
    index e93db09..21b0578 100644
    --- a/core/java/android/webkit/WebChromeClient.java
    +++ b/core/java/android/webkit/WebChromeClient.java
    
    @@ -69,7 +69,9 @@
     
         /**
          * Notify the host application that the current page would
    -     * like to show a custom View.
    +     * like to show a custom View.  This is used for Fullscreen
    +     * video playback; see "HTML5 Video support" documentation on
    +     * {@link WebView}.
          * @param view is the View object to be shown.
          * @param callback is the callback to be invoked if and when the view
          * is dismissed.
    @@ -84,7 +86,10 @@
          * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}.
          * @param callback is the callback to be invoked if and when the view
          * is dismissed.
    +     * @deprecated This method supports the obsolete plugin mechanism,
    +     * and will not be invoked in future
          */
    +    @Deprecated
         public void onShowCustomView(View view, int requestedOrientation,
                 CustomViewCallback callback) {};
         
    
    diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
    index e08052a..99e0ffb 100644
    --- a/core/java/android/webkit/WebViewDatabase.java
    +++ b/core/java/android/webkit/WebViewDatabase.java
    
    @@ -50,8 +50,10 @@
          *
          * @return true if there are any saved username/password pairs
          * @see WebView#savePassword
    -     * @see #clearUsernamePassword
    +     * @see #clearUsernamePassworda
    +     * @deprecated Saving passwords in WebView will not be supported in future versions.
          */
    +    @Deprecated
         public boolean hasUsernamePassword() {
             throw new MustOverrideException();
         }
    @@ -62,7 +64,9 @@
          *
          * @see WebView#savePassword
          * @see #hasUsernamePassword
    +     * @deprecated Saving passwords in WebView will not be supported in future versions.
          */
    +    @Deprecated
         public void clearUsernamePassword() {
             throw new MustOverrideException();
         }
    
    diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
    index cde6ceb..33fd8ce 100644
    --- a/core/java/android/widget/ImageView.java
    +++ b/core/java/android/widget/ImageView.java
    
    @@ -348,7 +348,7 @@
          * {@link #setImageBitmap(android.graphics.Bitmap)} and
          * {@link android.graphics.BitmapFactory} instead.</p>
          *
    -     * @param resId the resource identifier of the the drawable
    +     * @param resId the resource identifier of the drawable
          *
          * @attr ref android.R.styleable#ImageView_src
          */
    
    diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
    index 52b7a81..1246051 100644
    --- a/core/java/android/widget/TextView.java
    +++ b/core/java/android/widget/TextView.java
    
    @@ -5921,6 +5921,11 @@
             }
     
             Layout.Alignment alignment = getLayoutAlignment();
    +        final boolean testDirChange = mSingleLine && mLayout != null &&
    +            (alignment == Layout.Alignment.ALIGN_NORMAL ||
    +             alignment == Layout.Alignment.ALIGN_OPPOSITE);
    +        int oldDir = 0;
    +        if (testDirChange) oldDir = mLayout.getParagraphDirection(0);
             boolean shouldEllipsize = mEllipsize != null && getKeyListener() == null;
             final boolean switchEllipsize = mEllipsize == TruncateAt.MARQUEE &&
                     mMarqueeFadeMode != MARQUEE_FADE_NORMAL;
    @@ -6009,7 +6014,7 @@
                 }
             }
     
    -        if (bringIntoView) {
    +        if (bringIntoView || (testDirChange && oldDir != mLayout.getParagraphDirection(0))) {
                 registerForPreDraw();
             }
     
    
    diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
    index 00ecd0a..1315291 100644
    --- a/core/jni/android_os_Trace.cpp
    +++ b/core/jni/android_os_Trace.cpp
    
    @@ -27,6 +27,18 @@
     
     namespace android {
     
    +static void sanitizeString(String8& utf8Chars) {
    +    size_t size = utf8Chars.size();
    +    char* str = utf8Chars.lockBuffer(size);
    +    for (size_t i = 0; i < size; i++) {
    +        char c = str[i];
    +        if (c == '\0' || c == '\n' || c == '|') {
    +            str[i] = ' ';
    +        }
    +    }
    +    utf8Chars.unlockBuffer();
    +}
    +
     static jlong android_os_Trace_nativeGetEnabledTags(JNIEnv* env, jclass clazz) {
         return atrace_get_enabled_tags();
     }
    @@ -41,17 +53,8 @@
             jlong tag, jstring nameStr) {
         const size_t MAX_SECTION_NAME_LEN = 127;
         ScopedStringChars jchars(env, nameStr);
    -    String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()),
    -            jchars.size());
    -    size_t size = utf8Chars.size();
    -    char* str = utf8Chars.lockBuffer(size);
    -    for (size_t i = 0; i < size; i++) {
    -        char c = str[i];
    -        if (c == '\0' || c == '\n' || c == '|') {
    -            str[i] = ' ';
    -        }
    -    }
    -    utf8Chars.unlockBuffer();
    +    String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
    +    sanitizeString(utf8Chars);
         atrace_begin(tag, utf8Chars.string());
     }
     
    @@ -60,6 +63,24 @@
         atrace_end(tag);
     }
     
    +static void android_os_Trace_nativeAsyncTraceBegin(JNIEnv* env, jclass clazz,
    +        jlong tag, jstring nameStr, jint cookie) {
    +    const size_t MAX_SECTION_NAME_LEN = 127;
    +    ScopedStringChars jchars(env, nameStr);
    +    String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
    +    sanitizeString(utf8Chars);
    +    atrace_async_begin(tag, utf8Chars.string(), cookie);
    +}
    +
    +static void android_os_Trace_nativeAsyncTraceEnd(JNIEnv* env, jclass clazz,
    +        jlong tag, jstring nameStr, jint cookie) {
    +    const size_t MAX_SECTION_NAME_LEN = 127;
    +    ScopedStringChars jchars(env, nameStr);
    +    String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
    +    sanitizeString(utf8Chars);
    +    atrace_async_end(tag, utf8Chars.string(), cookie);
    +}
    +
     static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv* env,
             jclass clazz, jboolean allowed) {
         atrace_set_debuggable(allowed);
    @@ -79,6 +100,12 @@
         { "nativeTraceEnd",
                 "(J)V",
                 (void*)android_os_Trace_nativeTraceEnd },
    +    { "nativeAsyncTraceBegin",
    +            "(JLjava/lang/String;I)V",
    +            (void*)android_os_Trace_nativeAsyncTraceBegin },
    +    { "nativeAsyncTraceEnd",
    +            "(JLjava/lang/String;I)V",
    +            (void*)android_os_Trace_nativeAsyncTraceEnd },
         { "nativeSetAppTracingAllowed",
                 "(Z)V",
                 (void*)android_os_Trace_nativeSetAppTracingAllowed },
    
    diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
    index 785bf13..dc4d945 100644
    --- a/core/jni/android_util_AssetManager.cpp
    +++ b/core/jni/android_util_AssetManager.cpp
    
    @@ -1642,7 +1642,7 @@
             (void*) android_content_AssetManager_getAssetLength },
         { "getAssetRemainingLength", "(I)J",
             (void*) android_content_AssetManager_getAssetRemainingLength },
    -    { "addAssetPath",   "(Ljava/lang/String;)I",
    +    { "addAssetPathNative", "(Ljava/lang/String;)I",
             (void*) android_content_AssetManager_addAssetPath },
         { "isUpToDate",     "()Z",
             (void*) android_content_AssetManager_isUpToDate },
    
    diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
    index ce76d40..ea194fc 100644
    --- a/core/res/res/values-af/strings.xml
    +++ b/core/res/res/values-af/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksaksies"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Bergingspasie word min"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sommige stelselfunksies werk moontlik nie"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> loop tans"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Raak vir meer inligting of om die program te stop."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Toeganklikheid"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Muurpapier"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Verander muurpapier"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Kennisgewingluisteraar"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN geaktiveer"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN is geaktiveer deur <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Raak om die netwerk te bestuur."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Navigeer tuis"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Navigeer op"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Meer opsies"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s - %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s-%2$s%3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Interne geheue"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-berging"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Fout"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Hierdie program werk nie met rekeninge vir beperkte gebruikers nie"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Geen program gevind om hierdie handeling te hanteer nie"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Herroep"</string>
     </resources>
    
    diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
    index 132d4cc..84eba57 100644
    --- a/core/res/res/values-am/strings.xml
    +++ b/core/res/res/values-am/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ከመተግበሪያዎች በተለየ መልኩ እንዴት የአውታረ መረብ አጠቃቀም እንደተመዘገበ ለመቀየር ለመተግበሪያው ይፈቅዳሉ።ለመደበኛ መተግበሪያዎች አገልግሎት አይውልም።"</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"ማሳወቂያዎችን ይድረሱ"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ድንቦች አዘጋጅ"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"የፅሁፍ እርምጃዎች"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"የማከማቻ ቦታ እያለቀ ነው"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"አንዳንድ የስርዓት ተግባራት ላይሰሩ ይችላሉ"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> እያሄደ ነው"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"ተጨማሪ መረጃ ለማግኘት ወይም መተግበሪያውን ለማቆም ይንኩ።"</string>
         <string name="ok" msgid="5970060430562524910">"እሺ"</string>
         <string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
         <string name="yes" msgid="5362982303337969312">"እሺ"</string>
    @@ -1104,7 +1100,7 @@
         <string name="new_app_description" msgid="1932143598371537340">"የድሮውን ትግበራ ሳታስቀምጥ አቁም።"</string>
         <string name="sendText" msgid="5209874571959469142">"ለፅሁፍ ድርጊት ምረጥ"</string>
         <string name="volume_ringtone" msgid="6885421406845734650">"የስልክ ጥሪ ድምፅ"</string>
    -    <string name="volume_music" msgid="5421651157138628171">"ማህደረመረጃ ክፍልፍል"</string>
    +    <string name="volume_music" msgid="5421651157138628171">" ማህደረ መረጃ  ክፍልፍል"</string>
         <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"በብሉቱዝ በኩል ማጫወት"</string>
         <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"የፀጥታ የስልክ የደውል ድምፅ ተዘጋጅቷል"</string>
         <string name="volume_call" msgid="3941680041282788711">"የጥሪ ላይ ድም ፅ መጨመሪያ/መቀነሻ"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"ተደራሽነት"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"ልጣፍ"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"ልጣፍ ለውጥ"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"ማሳወቂያ አዳማጭ"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN ነቅቷል።"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN በ<xliff:g id="APP">%s</xliff:g>ገብሯል"</string>
         <string name="vpn_text" msgid="3011306607126450322">"አውታረመረብ ለማደራጀት  ንካ።"</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"መነሻ ዳስስ"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"አስስ"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"ተጨማሪ አማራጮች"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s፣ %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s፣ %2$s፣ %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"ውስጣዊ ማከማቻ"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD ካርድ"</string>
         <string name="storage_usb" msgid="3017954059538517278">"የUSB  ማከማቻ"</string>
    @@ -1398,7 +1391,7 @@
         <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"የተንቀሳቃሽ ውሂብ ወሰን አልፏል"</string>
         <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi ውሂብ ገደብ ታልፏል"</string>
         <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> ከተወሰነለት በላይ።"</string>
    -    <string name="data_usage_restricted_title" msgid="5965157361036321914">"በስተጀርባ ውሂብ የተገደበ ነው"</string>
    +    <string name="data_usage_restricted_title" msgid="5965157361036321914">"ዳራ ውሂብ የተገደበ ነው"</string>
         <string name="data_usage_restricted_body" msgid="6741521330997452990">"ገደብ ለማስወገድ ንካ።"</string>
         <string name="ssl_certificate" msgid="6510040486049237639">"የደህንነት ዕውቅና ማረጋገጫ"</string>
         <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"ይህ የዐዕውቅና ማረጋገጫ ትክክል ነው።"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"ስህተት"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"ይህ መተግበሪያ የተገደቡ ተጠቃሚዎች መለያዎችን አይደግፍም"</string>
         <string name="app_not_found" msgid="3429141853498927379">"ይህን እርምጃ የሚያከናውን ምንም መተግበሪያ አልተገኘም"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"ሻር"</string>
     </resources>
    
    diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
    index e13c0f2..d134ca4 100644
    --- a/core/res/res/values-ar/strings.xml
    +++ b/core/res/res/values-ar/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"للسماح للتطبيق بتعديل كيفية حساب استخدام الشبكة في التطبيقات. ليس للاستخدام بواسطة التطبيقات العادية."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"إشعارات الدخول"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"إجراءات النص"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"مساحة التخزين منخفضة"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"قد لا تعمل بعض وظائف النظام"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"المس للحصول على مزيد من المعلومات أو لإيقاف التطبيق."</string>
         <string name="ok" msgid="5970060430562524910">"موافق"</string>
         <string name="cancel" msgid="6442560571259935130">"إلغاء"</string>
         <string name="yes" msgid="5362982303337969312">"موافق"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"إمكانية الدخول"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"الخلفية"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"برنامج تلقّي الإشعارات الصوتية"</string>
         <string name="vpn_title" msgid="19615213552042827">"تم تنشيط الشبكة الظاهرية الخاصة (VPN)"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"تم تنشيط VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"المس لإدارة الشبكة."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"التنقل إلى الشاشة الرئيسية"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"التنقل إلى أعلى"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"المزيد من الخيارات"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s، %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s، %2$s، %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"وحدة تخزين داخلية"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"بطاقة SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"وحدة تخزين USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"خطأ"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"لا يوفر هذا التطبيق حسابات للمستخدمين المقيّدين"</string>
         <string name="app_not_found" msgid="3429141853498927379">"لم يتم العثور على تطبيق يمكنه التعامل مع هذا الإجراء."</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"إلغاء"</string>
     </resources>
    
    diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
    index 6653ac1..9f3d3e6 100644
    --- a/core/res/res/values-be/strings.xml
    +++ b/core/res/res/values-be/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ да паведамленняў"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дазваляе прыкладанню атрымлiваць, правяраць i выдаляць апавяшчэннi, у тым лiку апублiкаваныя iншымi прыкладаннямi."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прывязка да службы апавяшчэння слухача"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дазваляе ўладальніку прывязвацца да верхняга ўзроўню інтэрфейсу службы  апавяшчэння слухачоў. Ніколі не патрэбнае для звычайных прыкладанняў."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Дзеянні з тэкстам"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Месца для захавання на зыходзе"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некаторыя сістэмныя функцыі могуць не працаваць"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> працуе"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Націсніце, каб атрымаць дадатковую інфармацыю або спыніць праграму."</string>
         <string name="ok" msgid="5970060430562524910">"ОК"</string>
         <string name="cancel" msgid="6442560571259935130">"Адмяніць"</string>
         <string name="yes" msgid="5362982303337969312">"ОК"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Спецыяльныя магчымасці"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Шпалеры"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Змена шпалер"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Слухач апавяшчэння"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN актываваны"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN актывуецца прыкладаннем <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Дакраніцеся, каб кіраваць сеткай."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Перайсці да пачатковай старонкі"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Перайсці ўверх"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Больш налад"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Унутраная памяць"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Памылка"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Гэтае прыкладанне не падтрымлівае уліковыя запісы для карыстальнікаў з абмежаванымі правамі"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Прыкладанне для гэтага дзеяння не знойдзенае"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Ануляваць"</string>
     </resources>
    
    diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
    index 3d3e195..0983b5e 100644
    --- a/core/res/res/values-bg/strings.xml
    +++ b/core/res/res/values-bg/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Разрешава на приложението да променя това как употребата на мрежа се отчита спрямо приложенията. Не е предназначено за нормални приложения."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"достъп до известията"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Разрешава на притежателя да се обвърже с интерфейса от първо ниво на услуга за слушател на известия. Нормалните приложения не би трябвало никога да се нуждаят от това."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Действия с текста"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Мястото в хранилището е на изчерпване"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Възможно е някои функции на системата да не работят"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> се изпълнява"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Докоснете за още информация или за да спрете приложението."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Отказ"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Достъпност"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известия"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN е активирана"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана от <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Докоснете за управление на мрежата."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Придвижване към „Начало“"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Придвижване нагоре"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Още опции"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"„%1$s“ – %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"„%1$s“, „%2$s“ – %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Вътрешно хранилище"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD карта"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB хранилище"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Грешка"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Това приложение не поддържа профили за потребители с ограничения"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Няма намерено приложение за извършване на това действие"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Отмяна"</string>
     </resources>
    
    diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
    index c96bef8..ccea866 100644
    --- a/core/res/res/values-ca/strings.xml
    +++ b/core/res/res/values-ca/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Accions de text"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"S\'està acabant l\'espai d\'emmagatzematge"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"És possible que algunes funcions del sistema no funcionin"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> s\'està executant"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Toca per obtenir més informació o bé per aturar l\'aplicació."</string>
         <string name="ok" msgid="5970060430562524910">"D\'acord"</string>
         <string name="cancel" msgid="6442560571259935130">"Cancel·la"</string>
         <string name="yes" msgid="5362982303337969312">"D\'acord"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilitat"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fons de pantalla"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Canvia el fons de pantalla"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Processador de notificacions"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ha activat VPN"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Toca per gestionar la xarxa."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Torna a la pàgina d\'inici"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Mou cap a dalt"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Més opcions"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Emmagatzematge intern"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Targeta SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Emmagatzematge USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Aquesta aplicació no admet comptes per a usuaris limitats"</string>
         <string name="app_not_found" msgid="3429141853498927379">"No s\'ha trobat cap aplicació per processar aquesta acció"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Revoca"</string>
     </resources>
    
    diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
    index 4738834..c9a84cb 100644
    --- a/core/res/res/values-cs/strings.xml
    +++ b/core/res/res/values-cs/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Operace s textem"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"V úložišti je málo místa"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Některé systémové funkce nemusí fungovat"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> je spuštěna"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Klepnutím zobrazíte další informace nebo ukončíte aplikaci."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Usnadnění"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Změnit tapetu"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikace poslouchající oznámení"</string>
         <string name="vpn_title" msgid="19615213552042827">"Síť VPN je aktivována"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Aplikace <xliff:g id="APP">%s</xliff:g> aktivovala síť VPN"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Dotykem zobrazíte správu sítě."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Přejít na plochu"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Přejít nahoru"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Další možnosti"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s – %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s – %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Interní úložiště"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Karta SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Úložiště USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Chyba"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Tato aplikace u omezeného počtu uživatelů nepodporuje účty"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Aplikace potřebná k provedení této akce nebyla nalezena"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Zrušit"</string>
     </resources>
    
    diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
    index 6c16e56..0c7cf72 100644
    --- a/core/res/res/values-da/strings.xml
    +++ b/core/res/res/values-da/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksthandlinger"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der er snart ikke mere lagerplads"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nogle systemfunktioner virker måske ikke"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> kører"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Tryk for at få flere oplysninger eller for at stoppe appen."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Annuller"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Tilgængelighed"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapet"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift tapet"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN er aktiveret."</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Tryk for at administrere netværket."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Naviger hjem"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Naviger op"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Flere valgmuligheder"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Internt lager"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-lager"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Fejl"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Denne applikation understøtter ikke konti for brugere med begrænsede rettigheder"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Der blev ikke fundet nogen applikation, der kan håndtere denne handling"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Tilbagekald"</string>
     </resources>
    
    diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
    index ead4004..c03aa70 100644
    --- a/core/res/res/values-de/strings.xml
    +++ b/core/res/res/values-de/strings.xml
    
    @@ -114,7 +114,7 @@
         <string name="httpErrorLookup" msgid="4711687456111963163">"URL wurde nicht gefunden."</string>
         <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Das Authentifizierungsschema für die Website wird nicht unterstützt."</string>
         <string name="httpErrorAuth" msgid="1435065629438044534">"Bei der Authentifizierung ist ein Fehler aufgetreten."</string>
    -    <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Authentifizierung via Proxy-Server ist fehlgeschlagen."</string>
    +    <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Authentifizierung via Proxyserver ist fehlgeschlagen."</string>
         <string name="httpErrorConnect" msgid="8714273236364640549">"Verbindung zum Server konnte nicht hergestellt werden."</string>
         <string name="httpErrorIO" msgid="2340558197489302188">"Kommunikation mit dem Server konnte nicht hergestellt werden. Bitte versuchen Sie es später erneut."</string>
         <string name="httpErrorTimeout" msgid="4743403703762883954">"Zeitüberschreitung bei Serververbindung."</string>
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Textaktionen"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der Speicherplatz wird knapp"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren möglicherweise nicht."</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird ausgeführt"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Für weitere Informationen oder zum Anhalten der App tippen"</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1072,7 +1068,7 @@
         <string name="noApplications" msgid="2991814273936504689">"Diese Aktion kann von keiner App ausgeführt werden."</string>
         <string name="aerr_title" msgid="1905800560317137752"></string>
         <string name="aerr_application" msgid="932628488013092776">"\"<xliff:g id="APPLICATION">%1$s</xliff:g>\" wurde beendet."</string>
    -    <string name="aerr_process" msgid="4507058997035697579">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> wurde beendet."</string>
    +    <string name="aerr_process" msgid="4507058997035697579">"Der Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" wurde beendet."</string>
         <string name="anr_title" msgid="4351948481459135709"></string>
         <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reagiert nicht."\n\n"Möchten Sie die App schließen?"</string>
         <string name="anr_activity_process" msgid="5776209883299089767">"Aktivität \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" reagiert nicht."\n\n"Möchten Sie sie beenden?"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Bedienungshilfen"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Hintergrund"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Hintergrund ändern"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Benachrichtigungs-Listener"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN aktiviert"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN wurde von <xliff:g id="APP">%s</xliff:g> aktiviert."</string>
         <string name="vpn_text" msgid="3011306607126450322">"Zum Verwalten des Netzwerks berühren"</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Zur Startseite navigieren"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Nach oben navigieren"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Weitere Optionen"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s. %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s. %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Interner Speicher"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-Karte"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-Speicher"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Fehler"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Diese App unterstützt keine Konten für eingeschränkte Nutzer."</string>
         <string name="app_not_found" msgid="3429141853498927379">"Für diese Aktion wurde keine App gefunden."</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Aufheben"</string>
     </resources>
    
    diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
    index ac4ec2e..6dcdbf1 100644
    --- a/core/res/res/values-el/strings.xml
    +++ b/core/res/res/values-el/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Ενέργειες κειμένου"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ο χώρος αποθήκευσης εξαντλείται"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ορισμένες λειτουργίες συστήματος ενδέχεται να μην λειτουργούν"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εκτελείται"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Αγγίξτε για περισσότερες πληροφορίες ή για να διακόψετε την εκτέλεση της εφαρμογής."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Ακύρωση"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Προσβασιμότητα"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Ταπετσαρία"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Υπηρεσία ακρόασης ειδοποίησης"</string>
         <string name="vpn_title" msgid="19615213552042827">"Το VPN ενεργοποιήθηκε"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Το VPN ενεργοποιήθηκε από την εφαρμογή <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Αγγίξτε για τη διαχείριση του δικτύου."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Πλοήγηση στην αρχική σελίδα"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Πλοήγηση προς τα επάνω"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Περισσότερες επιλογές"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Εσωτερικός χώρος αποθήκευσης"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Κάρτα SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Χώρος αποθήκευσης USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Σφάλμα"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Αυτή η εφαρμογή δεν υποστηρίζει λογαριασμούς για περιορισμένους χρήστες"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Δεν υπάρχει εφαρμογή για τη διαχείριση αυτής της ενέργειας"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Ανάκληση"</string>
     </resources>
    
    diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
    index 5285532..08283c4 100644
    --- a/core/res/res/values-en-rGB/strings.xml
    +++ b/core/res/res/values-en-rGB/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> is running"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Touch for more information or to stop the app."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibility"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Navigate home"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Navigate up"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"More options"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Internal storage"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD card"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"This application does not support accounts for limited users"</string>
         <string name="app_not_found" msgid="3429141853498927379">"No application found to handle this action"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Revoke"</string>
     </resources>
    
    diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
    index 20f0c33..98528f7 100644
    --- a/core/res/res/values-es-rUS/strings.xml
    +++ b/core/res/res/values-es-rUS/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio de almacenamiento"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no estén disponibles."</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Toca para obtener más información o para detener la aplicación."</string>
         <string name="ok" msgid="5970060430562524910">"Aceptar"</string>
         <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
         <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilidad"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Papel tapiz"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Agente de escucha de notificaciones"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Desplazarse hasta la página principal"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Desplazarse hacia arriba"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Más opciones"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Almacenamiento interno"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Tarjeta SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Esta aplicación no admite cuentas para usuarios restringidos."</string>
         <string name="app_not_found" msgid="3429141853498927379">"No se encontró una aplicación para manejar esta acción."</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Revocar"</string>
     </resources>
    
    diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
    index 7dc03bec..485e1bf 100644
    --- a/core/res/res/values-es/strings.xml
    +++ b/core/res/res/values-es/strings.xml
    
    @@ -559,8 +559,8 @@
         <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Permite que la aplicación modifique el estado de la conectividad de red."</string>
         <string name="permlab_changeTetherState" msgid="5952584964373017960">"cambiar conectividad de anclaje a red"</string>
         <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permite que la aplicación cambie el estado de la conectividad de red de anclaje."</string>
    -    <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar configuración de uso de datos de referencia"</string>
    -    <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Permite que la aplicación cambie los ajustes de uso de datos de referencia."</string>
    +    <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar configuración de uso de conexiones automáticas"</string>
    +    <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Permite que la aplicación cambie los ajustes de uso de conexiones automáticas."</string>
         <string name="permlab_accessWifiState" msgid="5202012949247040011">"ver conexiones Wi-Fi"</string>
         <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Permite que la aplicación vea información sobre conexión a redes Wi-Fi (por ejemplo, si está habilitada la conexión Wi-Fi y el nombre de los dispositivos Wi-Fi conectados)."</string>
         <string name="permlab_changeWifiState" msgid="6550641188749128035">"conectarse a redes Wi-Fi y desconectarse"</string>
    @@ -569,14 +569,14 @@
         <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos de una red Wi-Fi que utilicen direcciones de multidifusión, no solo al tablet. Utiliza más batería que el modo de no multidifusión."</string>
         <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Permite que la aplicación reciba paquetes enviados a todos los dispositivos de una red Wi-Fi que utilicen direcciones de multidifusión, no solo al teléfono. Utiliza más batería que el modo de no multidifusión."</string>
         <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"acceder a los ajustes de Bluetooth"</string>
    -    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permite que la aplicación configure el tablet Bluetooth local y que detecte dispositivos remotos y se sincronice con ellos."</string>
    -    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite que la aplicación configure el teléfono Bluetooth local y que detecte dispositivos remotos y se sincronice con ellos."</string>
    +    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permite que la aplicación configure el tablet Bluetooth local y que detecte dispositivos remotos y se vincule con ellos."</string>
    +    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite que la aplicación configure el teléfono Bluetooth local y que detecte dispositivos remotos y se vincule con ellos."</string>
         <string name="permlab_accessWimaxState" msgid="4195907010610205703">"conectarse a WiMAX y desconectarse de esta red"</string>
         <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Permite que la aplicación determine si está habilitada la conexión WiMAX y obtenga información sobre las redes WiMAX que están conectadas."</string>
         <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar estado de WiMAX"</string>
         <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que la aplicación conecte el tablet a redes WiMAX y lo desconecte de ellas."</string>
         <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que la aplicación conecte el teléfono a redes WiMAX y lo desconecte de ellas."</string>
    -    <string name="permlab_bluetooth" msgid="6127769336339276828">"sincronizarse con dispositivos Bluetooth"</string>
    +    <string name="permlab_bluetooth" msgid="6127769336339276828">"vincular con dispositivos Bluetooth"</string>
         <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que la aplicación acceda a la configuración de Bluetooth del tablet y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
         <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que la aplicación acceda a la configuración de Bluetooth del teléfono y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
         <string name="permlab_nfc" msgid="4423351274757876953">"controlar Comunicación de campo cercano (NFC)"</string>
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -704,7 +702,7 @@
         <string name="phoneTypeIsdn" msgid="8022453193171370337">"RDSI"</string>
         <string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string>
         <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Otro fax"</string>
    -    <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
    +    <string name="phoneTypeRadio" msgid="4093738079908667513">"Señal móvil"</string>
         <string name="phoneTypeTelex" msgid="3367879952476250512">"Télex"</string>
         <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
         <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Móvil del trabajo"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no funcionen."</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Toca para obtener más información o para detener la aplicación."</string>
         <string name="ok" msgid="5970060430562524910">"Aceptar"</string>
         <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
         <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilidad"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fondo de pantalla"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Detector de notificaciones"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN activada por <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Ir al escritorio"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Desplazarse hacia arriba"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Más opciones"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Almacenamiento interno"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Tarjeta SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
    @@ -1398,7 +1391,7 @@
         <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Límite de datos móviles superado"</string>
         <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Límite de datos Wi-Fi superado"</string>
         <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Límite superado en <xliff:g id="SIZE">%s</xliff:g>"</string>
    -    <string name="data_usage_restricted_title" msgid="5965157361036321914">"Datos de referencia restringidos"</string>
    +    <string name="data_usage_restricted_title" msgid="5965157361036321914">"Conexiones automáticas restringidas"</string>
         <string name="data_usage_restricted_body" msgid="6741521330997452990">"Toca para eliminar la restricción."</string>
         <string name="ssl_certificate" msgid="6510040486049237639">"Certificado de seguridad"</string>
         <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Este certificado es válido."</string>
    @@ -1427,7 +1420,7 @@
         <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
         <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Teléfono"</string>
         <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculares"</string>
    -    <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces del conector"</string>
    +    <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces de la base"</string>
         <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
         <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
         <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Esta aplicación no admite cuentas de usuarios limitados."</string>
         <string name="app_not_found" msgid="3429141853498927379">"No se ha encontrado ninguna aplicación que pueda realizar esta acción."</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Revocar"</string>
     </resources>
    
    diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
    index e78e169..d2d4d63 100644
    --- a/core/res/res/values-et/strings.xml
    +++ b/core/res/res/values-et/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"juurdepääsu märguanded"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"seo märguannete kuulamisteenusega"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Võimaldab omanikul siduda märguannete kuulamisteenuse ülemise taseme kasutajaliidese. Seda ei tohiks tavarakenduste puhul kunagi vaja olla."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstitoimingud"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Talletusruum saab täis"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Mõned süsteemifunktsioonid ei pruugi töötada"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> töötab"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Puudutage lisateabe saamiseks või rakenduse peatamiseks."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Tühista"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Juurdepääsetavus"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustapilt"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Muutke taustapilti"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Märguannete kuulamisteenus"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN on aktiveeritud"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Liigu avalehele"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Liigu üles"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Rohkem valikuid"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Sisemine salvestusruum"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-mäluseade"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Viga"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Rakendus ei toeta piiratud õigustega kasutajate kontosid"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Selle toimingu käsitlemiseks ei leitud ühtegi rakendust"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Tühista"</string>
     </resources>
    
    diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
    index 3ab64c0..f723c37 100644
    --- a/core/res/res/values-fa/strings.xml
    +++ b/core/res/res/values-fa/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"به برنامه اجازه می‎دهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامه‎های عادی نیست."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلان‌های دسترسی"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه می‌دهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. این هرگز برای برنامه‌های عادی ضروری نیست."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسه‎های مجاز در گذرواژه‌های بازکردن قفل صفحه را کنترل کنید."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"عملکردهای متنی"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"فضای ذخیره‌سازی رو به اتمام است"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> در حال اجرا است"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"برای کسب اطلاعات بیشتر یا توقف برنامه لمس کنید."</string>
         <string name="ok" msgid="5970060430562524910">"تأیید"</string>
         <string name="cancel" msgid="6442560571259935130">"لغو"</string>
         <string name="yes" msgid="5362982303337969312">"تأیید"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"قابلیت دسترسی"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"تصویر زمینه"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر تصویر زمینه"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"شنونده اعلان"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN فعال شد"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN توسط <xliff:g id="APP">%s</xliff:g> فعال شده است"</string>
         <string name="vpn_text" msgid="3011306607126450322">"برای مدیریت شبکه لمس کنید."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"رفتن به صفحهٔ اصلی"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"حرکت به بالا"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"سایر گزینه‌ها"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"‎%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"‎%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"حافظهٔ داخلی"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"کارت SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"حافظهٔ USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"خطا"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"این برنامه حساب‌های تعداد محدودی از کاربران را پشتیبانی نمی‌کند"</string>
         <string name="app_not_found" msgid="3429141853498927379">"برنامه‌ای برای انجام این عملکرد موجود نیست"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"لغو"</string>
     </resources>
    
    diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
    index 86a9fae..7f7f07a 100644
    --- a/core/res/res/values-fi/strings.xml
    +++ b/core/res/res/values-fi/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Antaa sovelluksen muokata, miten sovellusten verkonkäyttöä lasketaan. Ei tavallisten sovellusten käyttöön."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"käytä ilmoituksia"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sido ilmoituskuuntelijapalveluun"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Antaa sovelluksen sitoutua ilmoituskuuntelijan ylimmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstitoiminnot"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Tallennustila loppumassa"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kaikki järjestelmätoiminnot eivät välttämättä toimi"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> on käynnissä"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Hanki lisätietoja tai sulje sovellus koskettamalla."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Peruuta"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Esteettömyys"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustakuva"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Vaihda taustakuvaa"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Ilmoituskuuntelija"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN on aktivoitu"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> on aktivoinut VPN-yhteyden"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Voit hallinnoida verkkoa koskettamalla."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Siirry etusivulle"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Siirry ylös"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Lisää asetuksia"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Sisäinen tallennustila"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-kortti"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-tallennustila"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Virhe"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Tämä sovellus ei tue rajoitettujen käyttäjien tilejä"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Tätä toimintoa käsittelevää sovellusta ei löydy"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Peruuta"</string>
     </resources>
    
    diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
    index 3b539da8..65c4ce5 100644
    --- a/core/res/res/values-fr/strings.xml
    +++ b/core/res/res/values-fr/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet à l\'application de modifier l\'utilisation du réseau par les autres applications. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"accéder aux notifications"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Actions sur le texte"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> en cours d\'exécution"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Appuyez ici pour en savoir plus ou arrêter l\'application."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilité"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fond d\'écran"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Outil d\'écoute des notifications"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Retour à l\'accueil"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Parcourir vers le haut"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Plus d\'options"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Mémoire de stockage interne"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Carte SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Erreur"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Les comptes des utilisateurs en accès limité ne sont pas acceptés pour cette application."</string>
         <string name="app_not_found" msgid="3429141853498927379">"Aucune application trouvée pour gérer cette action."</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Révoquer"</string>
     </resources>
    
    diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
    index ac20919..79dbfff 100644
    --- a/core/res/res/values-hi/strings.xml
    +++ b/core/res/res/values-hi/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्लिकेशन को यह संशोधित करने देता है कि एप्‍लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्‍य एप्‍लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्लिकेशन को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्लिकेशन के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्‍क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"स्‍क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"पाठ क्रियाएं"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"संग्रहण स्‍थान समाप्‍त हो रहा है"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"हो सकता है कुछ सिस्टम फ़ंक्शन कार्य न करें"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> चल रहा है"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"अधिक जानकारी के लिए या एप्लिकेशन रोकने के लिए स्पर्श करें."</string>
         <string name="ok" msgid="5970060430562524910">"ठीक"</string>
         <string name="cancel" msgid="6442560571259935130">"रद्द करें"</string>
         <string name="yes" msgid="5362982303337969312">"ठीक"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"पहुंच-योग्यता"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना श्रवणकर्ता"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN को <xliff:g id="APP">%s</xliff:g> द्वारा सक्रिय किया गया है"</string>
         <string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबंधित करने के लिए स्‍पर्श करें."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"होम पर नेविगेट करें"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"ऊपर नेविगेट करें"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"अधिक विकल्प"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"आंतरिक संग्रहण"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD कार्ड"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB संग्रहण"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"त्रुटि"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"यह एप्लिकेशन सीमित उपयोगकर्ताओं के खातों का समर्थन नहीं करता है"</string>
         <string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई एप्लिकेशन नहीं मिला"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"निरस्‍त करें"</string>
     </resources>
    
    diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
    index 9569a6c..90b44d2 100644
    --- a/core/res/res/values-hr/strings.xml
    +++ b/core/res/res/values-hr/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje s tekstom"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda neće raditi"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> pokrenuta je"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Dodirnite za više informacija ili da biste zaustavili aplikaciju."</string>
         <string name="ok" msgid="5970060430562524910">"U redu"</string>
         <string name="cancel" msgid="6442560571259935130">"Odustani"</string>
         <string name="yes" msgid="5362982303337969312">"U redu"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Dostupnost"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadinska slika"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Promjena pozadinske slike"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Slušatelj obavijesti"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> aktivirala je VPN"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Kreni na početnu"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Kreni gore"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Više opcija"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Interna pohrana"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD kartica"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Pogreška"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Aplikacija ne podržava račune za ograničene korisnike"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Nije pronađena aplikacija za upravljanje ovom radnjom"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Opozovi"</string>
     </resources>
    
    diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
    index 61e3707..d71ac23 100644
    --- a/core/res/res/values-hu/strings.xml
    +++ b/core/res/res/values-hu/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lehetővé teszi az alkalmazás számára annak módosítását, hogy a hálózathasználatot hogyan számolják el az alkalmazások esetében. Normál alkalmazások nem használhatják."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"hozzáférési értesítések"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"csatlakozzon értesítésfigyelő szolgáltatáshoz"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lehetővé teszi a használó számára, hogy csatlakozzon egy értesítésfigyelő szolgáltatás legfelső szintű felületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Műveletek szöveggel"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kevés a szabad terület"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Előfordulhat, hogy néhány rendszerfunkció nem működik."</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg fut"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"További információért, illetve az alkalmazás leállításához érintse meg."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Mégse"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Kisegítő lehetőségek"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Háttérkép"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Háttérkép megváltoztatása"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Értesítésfigyelő"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN aktiválva"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"A(z) <xliff:g id="APP">%s</xliff:g> aktiválta a VPN-t"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Érintse meg a hálózat kezeléséhez."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Ugrás a főoldalra"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Felfele mozgás"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"További lehetőségek"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Belső tárhely"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-kártya"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-tár"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Hiba"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ez az alkalmazás nem támogatja a korlátozott jogokkal rendelkező felhasználói fiókokat."</string>
         <string name="app_not_found" msgid="3429141853498927379">"Nincs megfelelő alkalmazás a művelet elvégzésére."</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Visszavonás"</string>
     </resources>
    
    diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
    index f4664e9..a9b33de 100644
    --- a/core/res/res/values-in/strings.xml
    +++ b/core/res/res/values-in/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Mengizinkan apl memodifikasi cara penggunaan jaringan diperhitungkan terhadap apl. Tidak untuk digunakan oleh apl normal."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"mengakses pemberitahuan"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mengikat layanan pendengar pemberitahuan"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Memungkinkan pemegang mengikat antarmuka tingkat teratas dari suatu layanan pendengar pemberitahuan. Tidak pernah diperlukan oleh aplikasi normal."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Tindakan teks"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang penyimpanan hampir habis"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak dapat bekerja"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Sentuh untuk informasi selengkapnya atau hentikan aplikasi."</string>
         <string name="ok" msgid="5970060430562524910">"Oke"</string>
         <string name="cancel" msgid="6442560571259935130">"Batal"</string>
         <string name="yes" msgid="5362982303337969312">"Oke"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Aksesibilitas"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Ubah wallpaper"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengelola jaringan."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Navigasi ke beranda"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Navigasi naik"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Opsi lainnya"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Penyimpanan internal"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Kartu SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Penyimpanan USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Kesalahan"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Aplikasi ini tidak mendukung akun untuk pengguna terbatas"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Tidak ada aplikasi yang ditemukan untuk menangani tindakan ini"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Cabut"</string>
     </resources>
    
    diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
    index 592492a..560b049 100644
    --- a/core/res/res/values-it/strings.xml
    +++ b/core/res/res/values-it/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Azioni testo"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spazio di archiviazione in esaurimento"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Alcune funzioni di sistema potrebbero non funzionare"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> è in esecuzione"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Tocca per ulteriori informazioni o per interrompere l\'app."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Annulla"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilità"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Sfondo"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener di notifica"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN attiva"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN attivata da <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Tocca per gestire la rete."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Vai alla home page"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Vai in alto"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Altre opzioni"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Memoria interna"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Scheda SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Archivio USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Errore"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Questa applicazione non supporta account di utenti con limitazioni"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Nessuna applicazione trovata in grado di gestire questa azione"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Revoca"</string>
     </resources>
    
    diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
    index 97c52c5..42f0e2d 100644
    --- a/core/res/res/values-iw/strings.xml
    +++ b/core/res/res/values-iw/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"הרשאה זו מאפשרת ליישום לשנות את אופן החישוב של נתוני שימוש ברשת מול כל יישום. לא מיועד לשימוש ביישומים רגילים."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"גישה להתראות"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר ליישום לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי יישומים אחרים."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה ליישומים רגילים."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"פעולות טקסט"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"שטח האחסון אוזל"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"ייתכן שפונקציות מערכת מסוימות לא יפעלו"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> פועל"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"גע לקבלת מידע נוסף או כדי לעצור את היישום."</string>
         <string name="ok" msgid="5970060430562524910">"אישור"</string>
         <string name="cancel" msgid="6442560571259935130">"ביטול"</string>
         <string name="yes" msgid="5362982303337969312">"אישור"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"נגישות"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"טפט"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"מאזין להתראות"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN מופעל"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"גע כדי לנהל את הרשת."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"נווט לדף הבית"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"נווט למעלה"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"אפשרויות נוספות"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s‏, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s‏, %2$s‏, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"אחסון פנימי"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"כרטיס SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"אחסון USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"שגיאה"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"היישום הזה לא תומך בחשבונות עבור משתמשים מוגבלים"</string>
         <string name="app_not_found" msgid="3429141853498927379">"לא נמצא יישום שתומך בפעולה זו"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"בטל"</string>
     </resources>
    
    diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
    index 0abacb1..f6b93f9 100644
    --- a/core/res/res/values-ja/strings.xml
    +++ b/core/res/res/values-ja/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"アプリに対するネットワーク利用の計算方法を変更することをアプリに許可します。通常のアプリでは使用しません。"</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"通知にアクセス"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"通知リスナーサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"テキスト操作"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"空き容量わずか"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"一部のシステム機能が動作しない可能性があります"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g>を実行しています"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"タップすると詳細が表示されるか、アプリが停止します。"</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"キャンセル"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"ユーザー補助"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"壁紙"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知リスナー"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPNが有効になりました"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPNが<xliff:g id="APP">%s</xliff:g>により有効化されました"</string>
         <string name="vpn_text" msgid="3011306607126450322">"タップしてネットワークを管理します。"</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"ホームへ移動"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"上へ移動"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"その他のオプション"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s、%2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s、%2$s、%3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"内部ストレージ"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SDカード"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USBストレージ"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"エラー"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"このアプリでは限定ユーザー用のアカウントはサポートしていません"</string>
         <string name="app_not_found" msgid="3429141853498927379">"この操作を行うアプリが見つかりません"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"取り消し"</string>
     </resources>
    
    diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
    index b07878c..5f50ac4 100644
    --- a/core/res/res/values-ko/strings.xml
    +++ b/core/res/res/values-ko/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"애플리케이션이 애플리케이션의 네트워크 사용량을 계산하는 방식을 수정할 수 있도록 허용합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"알림 액세스"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"권한을 가진 프로그램이 알림 수신기 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"텍스트 작업"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"저장 공간이 부족함"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"일부 시스템 기능이 작동하지 않을 수 있습니다."</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g>이(가) 실행 중입니다."</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"자세한 정보를 보거나 앱을 중지하려면 터치하세요."</string>
         <string name="ok" msgid="5970060430562524910">"확인"</string>
         <string name="cancel" msgid="6442560571259935130">"취소"</string>
         <string name="yes" msgid="5362982303337969312">"확인"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"접근성"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"배경화면"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"알림 수신기"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN이 활성화됨"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN이 <xliff:g id="APP">%s</xliff:g>에 의해 활성화됨"</string>
         <string name="vpn_text" msgid="3011306607126450322">"네트워크를 관리하려면 터치하세요."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"홈 탐색"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"위로 탐색"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"옵션 더보기"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"내부 저장소"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD 카드"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB 저장소"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"오류"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"이 애플리케이션은 제한된 사용자를 위한 계정을 지원하지 않습니다."</string>
         <string name="app_not_found" msgid="3429141853498927379">"이 작업을 처리하는 애플리케이션을 찾을 수 없습니다."</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"취소"</string>
     </resources>
    
    diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
    index 1b7b68e..9237a2c 100644
    --- a/core/res/res/values-lt/strings.xml
    +++ b/core/res/res/values-lt/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Leidžiama programai keisti, kaip tinklas naudojamas, palyginti su programomis. Neskirta naudoti įprastoms programoms."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"pasiekti pranešimus"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"susisaistyti su pranešimų skaitymo priemonės paslauga"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Leidžiama turėtojui susisaistyti su pranešimų skaitymo priemonės paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksto veiksmai"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Mažėja laisvos saugyklos vietos"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kai kurios sistemos funkcijos gali neveikti"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ vykdoma"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Palieskite, jei norite gauti daugiau informacijos arba sustabdyti programą."</string>
         <string name="ok" msgid="5970060430562524910">"Gerai"</string>
         <string name="cancel" msgid="6442560571259935130">"Atšaukti"</string>
         <string name="yes" msgid="5362982303337969312">"Gerai"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Pasiekiamumas"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Darbalaukio fonas"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Keisti darbalaukio foną"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Pranešimų skaitymo priemonė"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN suaktyvintas"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN suaktyvino „<xliff:g id="APP">%s</xliff:g>“"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Palieskite, kad valdytumėte tinklą."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Naršyti pagrindinį puslapį"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Naršyti į viršų"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Daugiau parinkčių"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Vidinė atmintis"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD kortelė"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB atmintis"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Klaida"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ši programa nepalaiko apribotų naudotojų paskyrų"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Nerasta programa šiam veiksmui apdoroti"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Anuliuoti"</string>
     </resources>
    
    diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
    index 9ae5381d..1de841e 100644
    --- a/core/res/res/values-lv/strings.xml
    +++ b/core/res/res/values-lv/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ļauj lietotnei mainīt to, kā tīkla lietojums tiek uzskaitīts saistībā ar lietotnēm. Atļauja neattiecas uz parastām lietotnēm."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"piekļuve paziņojumiem"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"saites izveidošana ar paziņojumu uztvērēja pakalpojumu"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ļauj īpašniekam izveidot saiti ar paziņojumu uztvērēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksta darbības"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Paliek maz brīvas vietas"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Dažas sistēmas funkcijas var nedarboties."</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> darbojas"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Pieskarieties, lai iegūtu plašāku informāciju vai apturētu lietotnes darbību."</string>
         <string name="ok" msgid="5970060430562524910">"Labi"</string>
         <string name="cancel" msgid="6442560571259935130">"Atcelt"</string>
         <string name="yes" msgid="5362982303337969312">"Labi"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Pieejamība"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fona tapete"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Tapetes maiņa"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Paziņojumu uztvērējs"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN ir aktivizēts."</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Lietojumprogramma <xliff:g id="APP">%s</xliff:g> aktivizēja VPN."</string>
         <string name="vpn_text" msgid="3011306607126450322">"Pieskarieties, lai pārvaldītu tīklu."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Pārvietoties uz sākuma ekrānu"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Pārvietoties augšup"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Vairāk opciju"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s: %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s: %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Iekšējā atmiņa"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD karte"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB atmiņa"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Kļūda"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Šajā lietojumprogrammā netiek atbalstīti ierobežotu lietotāju konti."</string>
         <string name="app_not_found" msgid="3429141853498927379">"Netika atrasta neviena lietojumprogramma, kas var veikt šo darbību."</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Atsaukt"</string>
     </resources>
    
    diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
    index bbde90d..af5b866 100644
    --- a/core/res/res/values-ms/strings.xml
    +++ b/core/res/res/values-ms/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Membenarkan apl untuk mengubah suai bagaimana penggunaan rangkaian diambil kira terhadap apl. Bukan untuk digunakan oleh apl biasa."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"pemberitahuan akses"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ikat kepada perkhidmatan pendengar pemberitahuan"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pendengar pemberitahuan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Tindakan teks"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang storan semakin berkurangan"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak berfungsi"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Sentuh untuk maklumat lanjut atau untuk menghentikan apl."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Batal"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Kebolehaksesan"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Kertas dinding"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Tukar kertas dinding"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengurus rangkaian."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Navigasi laman utama"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Navigasi ke atas"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Lagi pilihan"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Storan dalaman"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Kad SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Storan USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Ralat"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Aplikasi ini tidak menyokong akaun untuk pengguna terhad"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Tidak menemui aplikasi untuk mengendalikan tindakan ini"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Batalkan"</string>
     </resources>
    
    diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
    index 3bb5022..e0d9bf2 100644
    --- a/core/res/res/values-nb/strings.xml
    +++ b/core/res/res/values-nb/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lar appen endre hvordan nettverksbruk regnes ut for apper. Ikke beregnet på vanlige apper."</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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksthandlinger"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lite ledig lagringsplass"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Enkelte systemfunksjoner fungerer muligens ikke slik de skal"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> kjører"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Trykk for mer informasjon, eller for å stoppe appen."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Tilgjengelighet"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrunnsbilde"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Velg bakgrunnsbilde"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Varsellytteren"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN er aktivert"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN er aktivert av <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Trykk for å administrere nettverket."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Gå til startsiden"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Gå opp"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Flere alternativer"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s – %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s – %2$s – %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Intern lagring"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Feil"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Denne appen støtter ikke kontoer for brukere med begrensninger"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Finner ingen apper som kan utføre denne handlingen"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Opphev"</string>
     </resources>
    
    diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
    index 4d71f08..2e92761 100644
    --- a/core/res/res/values-nl/strings.xml
    +++ b/core/res/res/values-nl/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstacties"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Opslagruimte is bijna vol"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bepaalde systeemfuncties werken mogelijk niet"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> wordt uitgevoerd"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Raak aan voor meer informatie of om de app te stoppen."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Toegankelijkheid"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Achtergrond"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Achtergrond wijzigen"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener voor meldingen"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN is geactiveerd"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN wordt geactiveerd door <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Raak aan om het netwerk te beheren."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Navigeren naar startpositie"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Omhoog navigeren"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Meer opties"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Interne opslag"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-opslag"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Fout"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Deze app ondersteunt geen accounts voor beperkte gebruikers"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Er is geen app gevonden om deze actie uit te voeren"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Intrekken"</string>
     </resources>
    
    diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
    index f4fe466..d8a4bf9 100644
    --- a/core/res/res/values-pl/strings.xml
    +++ b/core/res/res/values-pl/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pozwala aplikacji na zmienianie sposobu rozliczania wykorzystania sieci przez aplikacje. Nieprzeznaczone dla zwykłych aplikacji."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostęp do powiadomień"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"utwórz połączenie z usługą odbiornika powiadomień"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi odbiornika powiadomień. Nie powinno być nigdy potrzebne dla zwykłych aplikacji."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Działania na tekście"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kończy się miejsce"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektóre funkcje systemu mogą nie działać"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest uruchomiona"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Kliknij, aby uzyskać więcej informacji lub zatrzymać aplikację."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Ułatwienia dostępu"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Zmień tapetę"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Odbiornik powiadomień"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN aktywny"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Obsługa sieci VPN została włączona przez aplikację <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Dotknij, aby zarządzać siecią."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Przejdź do strony głównej"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Przejdź wyżej"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Więcej opcji"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Pamięć wewnętrzna"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Karta SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Nośnik USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Błąd"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ta aplikacja nie obsługuje kont użytkowników z ograniczeniami"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Nie znaleziono aplikacji do obsługi tej akcji"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Cofnij"</string>
     </resources>
    
    diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
    index 36751b1..66d50e6 100644
    --- a/core/res/res/values-pt-rPT/strings.xml
    +++ b/core/res/res/values-pt-rPT/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Acções de texto"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Está quase sem espaço de armazenamento"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema poderão não funcionar"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> em execução"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Toque para obter mais informações ou para parar a aplicação."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Acessibilidade"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagem de fundo"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar imagem de fundo"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviço de escuta de notificações"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"A VPN foi ativada pelo <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Toque para gerir a rede."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Navegar para página inicial"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Navegar para cima"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"memória de armazenamento interno"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Erro"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Esta aplicação não suporta contas de utilizadores limitados"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Não foram encontradas aplicações para executar esta ação"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Revogar"</string>
     </resources>
    
    diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
    index 61716fe..3877158 100644
    --- a/core/res/res/values-pt/strings.xml
    +++ b/core/res/res/values-pt/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que o aplicativo modifique como o uso da rede é contabilizado em relação aos aplicativos. Não deve ser usado em aplicativos normais."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"acessar notificações"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sujeitar a um serviço ouvinte de notificações"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o proprietário sujeite a interface de nível superior a um serviço ouvinte de notificações. Não deve ser necessário para aplicativos comuns."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controle o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Ações de texto"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> está em execução"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Toque para mais informações ou para parar o aplicativo."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Acessibilidade"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Plano de fundo"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar plano de fundo"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Ouvinte de notificações"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Navegar na página inicial"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Navegar para cima"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Armazenamento interno"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Erro"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"O aplicativo não suporta contas para usuários limitados"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Nenhum aplicativo encontrado para executar a ação"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Revogar"</string>
     </resources>
    
    diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
    index 003f932..21fcf04 100644
    --- a/core/res/res/values-ro/strings.xml
    +++ b/core/res/res/values-ro/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicaţiei să modifice modul în care este calculată utilizarea reţelei pentru aplicaţii. Nu se utilizează de aplicaţiile obişnuite."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Acţiuni pentru text"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spaţiul de stocare aproape ocupat"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcţii de sistem să nu funcţioneze"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> rulează acum"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Atingeți pentru mai multe informații sau pentru a opri aplicația."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Anulaţi"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilitate"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagine de fundal"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Modificaţi imaginea de fundal"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviciu de citire a notificărilor"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN activat"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Atingeţi pentru a gestiona reţeaua."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Navigaţi la ecranul de pornire"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Navigaţi în sus"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mai multe opţiuni"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Stocare internă"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Card SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Eroare"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Această aplicație nu acceptă conturile pentru utilizatori cu permisiuni limitate"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Nicio aplicație pentru gestionarea acestei acțiuni"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Revocați"</string>
     </resources>
    
    diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
    index 2c8dfe8..592271b 100644
    --- a/core/res/res/values-ru/strings.xml
    +++ b/core/res/res/values-ru/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Приложение сможет изменять порядок расчета использования сетевых ресурсов различными программами. Это разрешение не используется обычными приложениями."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ к уведомлениям"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"подключить к службе просмотра уведомлений"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Операции с текстом"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Заканчивается свободное место"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некоторые системные функции могут не работать"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" выполняется"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Нажмите, чтобы получить дополнительные данные или выключить приложение."</string>
         <string name="ok" msgid="5970060430562524910">"ОК"</string>
         <string name="cancel" msgid="6442560571259935130">"Отмена"</string>
         <string name="yes" msgid="5362982303337969312">"ОК"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Спец. возможности"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновый рисунок"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба просмотра уведомлений"</string>
         <string name="vpn_title" msgid="19615213552042827">"Сеть VPN активна"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Сеть VPN активирована приложением <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Нажмите, чтобы открыть настройки."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Перейти на главную"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Перейти вверх"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Ещё"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Внутренняя память"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-накопитель"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Ошибка"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Приложение не поддерживает аккаунты с ограниченным доступом"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Невозможно обработать это действие"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Отменить"</string>
     </resources>
    
    diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
    index 80a2c31..228a9e7 100644
    --- a/core/res/res/values-sk/strings.xml
    +++ b/core/res/res/values-sk/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -648,7 +646,7 @@
         <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Zákaz funkcie v zámke kláves."</string>
         <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Zabrániť používaniu niektorých funkcií v zámke klávesov."</string>
       <string-array name="phoneTypes">
    -    <item msgid="8901098336658710359">"Domovská stránka"</item>
    +    <item msgid="8901098336658710359">"Domov"</item>
         <item msgid="869923650527136615">"Mobil"</item>
         <item msgid="7897544654242874543">"Práca"</item>
         <item msgid="1103601433382158155">"Fax do práce"</item>
    @@ -658,19 +656,19 @@
         <item msgid="9192514806975898961">"Vlastné"</item>
       </string-array>
       <string-array name="emailAddressTypes">
    -    <item msgid="8073994352956129127">"Domovská stránka"</item>
    +    <item msgid="8073994352956129127">"Domov"</item>
         <item msgid="7084237356602625604">"Práca"</item>
         <item msgid="1112044410659011023">"Iné"</item>
         <item msgid="2374913952870110618">"Vlastné"</item>
       </string-array>
       <string-array name="postalAddressTypes">
    -    <item msgid="6880257626740047286">"Domovská stránka"</item>
    +    <item msgid="6880257626740047286">"Domov"</item>
         <item msgid="5629153956045109251">"Práca"</item>
         <item msgid="4966604264500343469">"Iné"</item>
         <item msgid="4932682847595299369">"Vlastné"</item>
       </string-array>
       <string-array name="imAddressTypes">
    -    <item msgid="1738585194601476694">"Domovská stránka"</item>
    +    <item msgid="1738585194601476694">"Domov"</item>
         <item msgid="1359644565647383708">"Práca"</item>
         <item msgid="7868549401053615677">"Iné"</item>
         <item msgid="3145118944639869809">"Vlastné"</item>
    @@ -691,7 +689,7 @@
         <item msgid="1648797903785279353">"Jabber"</item>
       </string-array>
         <string name="phoneTypeCustom" msgid="1644738059053355820">"Vlastné"</string>
    -    <string name="phoneTypeHome" msgid="2570923463033985887">"Domovská stránka"</string>
    +    <string name="phoneTypeHome" msgid="2570923463033985887">"Domov"</string>
         <string name="phoneTypeMobile" msgid="6501463557754751037">"Mobil"</string>
         <string name="phoneTypeWork" msgid="8863939667059911633">"Práca"</string>
         <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Fax do práce"</string>
    @@ -716,16 +714,16 @@
         <string name="eventTypeAnniversary" msgid="3876779744518284000">"Výročie"</string>
         <string name="eventTypeOther" msgid="7388178939010143077">"Iné"</string>
         <string name="emailTypeCustom" msgid="8525960257804213846">"Vlastné"</string>
    -    <string name="emailTypeHome" msgid="449227236140433919">"Domovská stránka"</string>
    +    <string name="emailTypeHome" msgid="449227236140433919">"Domov"</string>
         <string name="emailTypeWork" msgid="3548058059601149973">"Práca"</string>
         <string name="emailTypeOther" msgid="2923008695272639549">"Iné"</string>
         <string name="emailTypeMobile" msgid="119919005321166205">"Mobil"</string>
         <string name="postalTypeCustom" msgid="8903206903060479902">"Vlastné"</string>
    -    <string name="postalTypeHome" msgid="8165756977184483097">"Domovská stránka"</string>
    +    <string name="postalTypeHome" msgid="8165756977184483097">"Domov"</string>
         <string name="postalTypeWork" msgid="5268172772387694495">"Práca"</string>
         <string name="postalTypeOther" msgid="2726111966623584341">"Iné"</string>
         <string name="imTypeCustom" msgid="2074028755527826046">"Vlastné"</string>
    -    <string name="imTypeHome" msgid="6241181032954263892">"Domovská stránka"</string>
    +    <string name="imTypeHome" msgid="6241181032954263892">"Domov"</string>
         <string name="imTypeWork" msgid="1371489290242433090">"Práca"</string>
         <string name="imTypeOther" msgid="5377007495735915478">"Iné"</string>
         <string name="imProtocolCustom" msgid="6919453836618749992">"Vlastné"</string>
    @@ -757,7 +755,7 @@
         <string name="relationTypeSister" msgid="1735983554479076481">"Sestra"</string>
         <string name="relationTypeSpouse" msgid="394136939428698117">"Manžel(-ka)"</string>
         <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Vlastné"</string>
    -    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Domovská stránka"</string>
    +    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Domov"</string>
         <string name="sipAddressTypeWork" msgid="6920725730797099047">"Práca"</string>
         <string name="sipAddressTypeOther" msgid="4408436162950119849">"Iné"</string>
         <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Zadajte kód PIN"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Operácie s textom"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nedostatok ukladacieho priestoru"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektoré systémové funkcie nemusia fungovať"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> je spustená"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Dotknutím sa zobrazíte viac informácií alebo zastavíte aplikáciu."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Zjednodušenie"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Zmeniť tapetu"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikácia na počúvanie upozornení"</string>
         <string name="vpn_title" msgid="19615213552042827">"Sieť VPN je aktivovaná"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Aplikáciu <xliff:g id="APP">%s</xliff:g> aktivovala sieť VPN"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Dotykom môžete spravovať sieť."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Prejsť na plochu"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Prejsť na"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Viac možností"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Interné úložisko"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Karta SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Ukladací priestor USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Chyba"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Táto aplikácia nepodporuje účty v prípade používateľov s obmedzením"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Aplikácia potrebná na spracovanie tejto akcie sa nenašla"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Odvolať"</string>
     </resources>
    
    diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
    index 766b605..906c197 100644
    --- a/core/res/res/values-sl/strings.xml
    +++ b/core/res/res/values-sl/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Programu omogoča, da spremeni uporabo omrežja na podlagi programov. Ni za uporabo z navadnimi programi."</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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Besedilna dejanja"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za shranjevanje bo pošel"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nekatere sistemske funkcije morda ne delujejo"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvaja"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Dotaknite se, če želite izvedeti več ali ustaviti aplikacijo."</string>
         <string name="ok" msgid="5970060430562524910">"V redu"</string>
         <string name="cancel" msgid="6442560571259935130">"Prekliči"</string>
         <string name="yes" msgid="5362982303337969312">"V redu"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Pripomočki za osebe s posebnimi potrebami"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Ozadje"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Spreminjanje ozadja"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Poslušalec obvestil"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktiviral program <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Krmarjenje domov"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Krmarjenje navzgor"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Več možnosti"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Notranji pomnilnik"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Kartica SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Pomnilnik USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Napaka"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ta aplikacija ne podpira računov za uporabnike z omejitvami"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Najdena ni bila nobena aplikacija za izvedbo tega dejanja"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Prekliči"</string>
     </resources>
    
    diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
    index 15b9ec5..102ced6 100644
    --- a/core/res/res/values-sr/strings.xml
    +++ b/core/res/res/values-sr/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозвољава апликацији да измени начин на који апликације користе мрежу. Не користе је уобичајене апликације."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"приступ обавештењима"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Радње у вези са текстом"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Простор за складиштење је на измаку"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је покренута"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Додирните за више информација или заустављање апликације."</string>
         <string name="ok" msgid="5970060430562524910">"Потврди"</string>
         <string name="cancel" msgid="6442560571259935130">"Откажи"</string>
         <string name="yes" msgid="5362982303337969312">"Потврди"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Приступачност"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Позадина"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Монитор обавештења"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN је активиран"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Апликација <xliff:g id="APP">%s</xliff:g> је активирала VPN"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Додирните да бисте управљали мрежом."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Кретање до Почетне"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Кретање нагоре"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Још опција"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Интерна меморија"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD картица"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB меморија"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Грешка"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ова апликација не подржава налоге за кориснике са ограничењем"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Није пронађена ниједна апликација која би могла да обави ову радњу"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Опозови"</string>
     </resources>
    
    diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
    index 291681c..adeffc3 100644
    --- a/core/res/res/values-sv/strings.xml
    +++ b/core/res/res/values-sv/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillåter att appen ändrar hur nätverksanvändning redovisas för appar. Används inte av vanliga appar."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"få åtkomst till meddelanden"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binda till en meddelandelyssnare"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en meddelandelyssnare. Ska inte behövas för vanliga appar."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Textåtgärder"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lagringsutrymmet börjar ta slut"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Det kan hända att vissa systemfunktioner inte fungerar"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> körs"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Tryck om du vill veta mer eller stoppa appen."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Tillgänglighet"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrund"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Ändra bakgrund"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Meddelandelyssnare"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN är aktiverat"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveras av <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Tryck om du vill hantera nätverket."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Visa startsidan"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Navigera uppåt"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Fler alternativ"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Internminne"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Fel"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Appen har inte stöd för användarkonton med begränsningar"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Ingen app som kan hantera åtgärden hittades"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Återkalla"</string>
     </resources>
    
    diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
    index c8f1343..bdc0155 100644
    --- a/core/res/res/values-sw/strings.xml
    +++ b/core/res/res/values-sw/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Vitendo vya maandishi"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nafasi ya kuhafadhi inakwisha"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Baadhi ya vipengee vya mfumo huenda visifanye kazi"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> inaendesha"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Gusa ili upate maelezo zaidi au usitishe programu."</string>
         <string name="ok" msgid="5970060430562524910">"Sawa"</string>
         <string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
         <string name="yes" msgid="5362982303337969312">"Sawa"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Ufikiaji"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Mandhari"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha mandhari"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Kisikilizi cha arifa"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN imewezeshwa"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN imeamilishwa na <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Gusa ili kudhibiti mtandao."</string>
    @@ -1289,7 +1284,7 @@
         <string name="submit" msgid="1602335572089911941">"Wasilisha"</string>
         <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mtindo wa gari umewezeshwa"</string>
         <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Gusa ili kutoka katika modi ya gari."</string>
    -    <string name="tethered_notification_title" msgid="3146694234398202601">"Amilisha uzuiaji au mahali maalum"</string>
    +    <string name="tethered_notification_title" msgid="3146694234398202601">"Kushiriki au kusambaza intaneti kumewashwa"</string>
         <string name="tethered_notification_message" msgid="6857031760103062982">"Gusa ili kusanidi."</string>
         <string name="back_button_label" msgid="2300470004503343439">"Nyuma"</string>
         <string name="next_button_label" msgid="1080555104677992408">"Ifuatayo"</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Abiri nyumbani"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Ongoza"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Chaguo zaidi"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Hifadhi ya mfumo"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Kadi ya SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Hifadhi ya USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Hitilafu"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Programu hii haiwezi kutumiwa na akaunti za watumiaji waliowekewa vizuizi"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Hakuna programu iliyopatikana ili kushughulikia kitendo hiki"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Batilisha"</string>
     </resources>
    
    diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
    index 66b3199..a92db72 100644
    --- a/core/res/res/values-th/strings.xml
    +++ b/core/res/res/values-th/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"อนุญาตให้แอปพลิเคชันแก้ไขวิธีการบันทึกบัญชีการใช้งานเครือข่ายของแอปพลิเคชัน ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"เข้าถึงการแจ้งเตือน"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเตอร์เฟซระดับสูงสุดของบริการตัวฟังการแจ้งเตือน ซึ่งไม่มีความจำเป็นสำหรับแอปธรรมดา"</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"การทำงานของข้อความ"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"พื้นที่จัดเก็บเหลือน้อย"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"บางฟังก์ชันระบบอาจไม่ทำงาน"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังทำงาน"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"แตะเพื่อดูข้อมูลเพิ่มเติมหรือเพื่อหยุดแอป"</string>
         <string name="ok" msgid="5970060430562524910">"ตกลง"</string>
         <string name="cancel" msgid="6442560571259935130">"ยกเลิก"</string>
         <string name="yes" msgid="5362982303337969312">"ตกลง"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"การเข้าถึง"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"วอลเปเปอร์"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"ตัวฟังการแจ้งเตือน"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN เปิดใช้งานแล้ว"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"เปิดใช้งาน VPN โดย <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"แตะเพื่อจัดการเครือข่าย"</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"นำทางไปหน้าแรก"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"นำทางขึ้น"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"ตัวเลือกเพิ่มเติม"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"ที่จัดเก็บข้อมูลภายใน"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"การ์ด SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"ที่เก็บข้อมูล USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"ข้อผิดพลาด"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"แอปพลิเคชันนี้ไม่สนับสนุนบัญชีผู้ใช้ที่ถูกจำกัด"</string>
         <string name="app_not_found" msgid="3429141853498927379">"ไม่พบแอปพลิเคชันสำหรับการทำงานนี้"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"เพิกถอน"</string>
     </resources>
    
    diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
    index bd5f99d..e726333 100644
    --- a/core/res/res/values-tl/strings.xml
    +++ b/core/res/res/values-tl/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pinapayagan ang app na baguhin kung paano isinasaalang-alang ang paggamit ng network laban sa apps. Hindi para sa paggamit ng normal na apps."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"i-access ang mga notification"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mapailalim sa isang serbisyo ng notification listener"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nagbibigay-daan sa may-ari na mapailalim sa interface sa tuktok na antas ng isang serbisyo ng notification listener. Hindi dapat kailanganin para sa karaniwang apps kahit kailan."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Pagkilos ng teksto"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nauubusan na ang puwang ng storage"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Maaaring hindi gumana nang tama ang ilang paggana ng system"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"Tumatakbo ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Pindutin para sa higit pang impormasyon o upang ihinto ang app."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Kanselahin"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Kakayahang Ma-access"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Baguhin ang wallpaper"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
         <string name="vpn_title" msgid="19615213552042827">"Naka-activate ang VPN"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Isinaaktibo ang VPN ng <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Pindutin upang pamahalaan ang network."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Magnabiga sa home"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Magnabiga pataas"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Higit pang mga pagpipilian"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Panloob na storage"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD card"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Hindi sinusuportahan ng application na ito ang mga account para sa mga limitadong user"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Walang nakitang application na mangangasiwa sa pagkilos na ito"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Bawiin"</string>
     </resources>
    
    diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
    index 79c3706..9e5e43b 100644
    --- a/core/res/res/values-tr/strings.xml
    +++ b/core/res/res/values-tr/strings.xml
    
    @@ -621,10 +621,8 @@
         <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>
         <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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Metin eylemleri"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Depolama alanı bitiyor"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bazı sistem işlevleri çalışmayabilir"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> çalışıyor"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Daha fazla bilgi edinmek için veya uygulamayı durdurmak için dokunun."</string>
         <string name="ok" msgid="5970060430562524910">"Tamam"</string>
         <string name="cancel" msgid="6442560571259935130">"İptal"</string>
         <string name="yes" msgid="5362982303337969312">"Tamam"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Erişebilirlik"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Duvar Kağıdı"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Duvar kağıdını değiştir"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirim dinleyici"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN etkinleştirildi"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN, <xliff:g id="APP">%s</xliff:g> tarafından etkinleştirildi"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Ağı yönetmek için dokunun."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Ana sayfaya git"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Yukarı git"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Diğer seçenekler"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Dahili depolama birimi"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD kart"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB bellek"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Hata"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Bu uygulama, kısıtlı kullanıcı hesaplarını desteklemiyor"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Bu eylemi gerçekleştirecek bir uygulama bulunamadı"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"İptal et"</string>
     </resources>
    
    diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
    index ad206d3..bb223ea 100644
    --- a/core/res/res/values-uk/strings.xml
    +++ b/core/res/res/values-uk/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозволяє програмі змінювати метод підрахунку того, як програми використовують мережу. Не для використання звичайними програмами."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"отримувати доступ до сповіщень"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Дії з текстом"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Закінчується пам’ять"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Деякі системні функції можуть не працювати"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> працює"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Торкніться, щоб дізнатися більше або зупинити програму."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Скасувати"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Доступність"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновий мал."</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба читання сповіщень"</string>
         <string name="vpn_title" msgid="19615213552042827">"Мережу VPN активовано"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"Мережу VPN активовано програмою <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Торкніться, щоб керувати мережею."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Перейти на головну"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Перейти вгору"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Інші варіанти"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Внутрішня пам’ять"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Карта SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Носій USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Помилка"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ця програма не підтримує облікові записи для обмежених користувачів"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Не знайдено програму для обробки цієї дії"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Анулювати"</string>
     </resources>
    
    diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
    index 4022f04..a592144 100644
    --- a/core/res/res/values-vi/strings.xml
    +++ b/core/res/res/values-vi/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Cho phép ứng dụng sửa đổi cách tính mức sử dụng mạng so với ứng dụng. Không dành cho các ứng dụng thông thường."</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"truy cập thông báo"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"Cho phép ứng dụng truy xuất, kiểm tra và xóa thông báo, bao gồm những thông báo được đăng bởi các ứng dụng khác."</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"liên kết với dịch vụ trình xử lý thông báo"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ trình xử lý thông báo. Không cần thiết cho các ứng dụng thông thường."</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kiểm soát độ dài và ký tự được phép trong mật khẩu mở khóa màn hình."</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Tác vụ văn bản"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Sắp hết dung lượng lưu trữ"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Một số chức năng hệ thống có thể không hoạt động"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang chạy"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Chạm để xem thêm thông tin hoặc dừng ứng dụng."</string>
         <string name="ok" msgid="5970060430562524910">"OK"</string>
         <string name="cancel" msgid="6442560571259935130">"Hủy"</string>
         <string name="yes" msgid="5362982303337969312">"OK"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Khả năng truy cập"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Hình nền"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Thay đổi hình nền"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Trình xử lý thông báo"</string>
         <string name="vpn_title" msgid="19615213552042827">"Đã kích hoạt VPN"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"VPN được <xliff:g id="APP">%s</xliff:g> kích hoạt"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Chạm để quản lý mạng."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Điều hướng về trang chủ"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Điều hướng lên trên"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Tùy chọn khác"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Bộ nhớ trong"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Thẻ SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Bộ lưu trữ USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Lỗi"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ứng dụng này không hỗ trợ tài khoản cho người dùng giới hạn"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Không tìm thấy ứng dụng nào để xử lý tác vụ này"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Thu hồi"</string>
     </resources>
    
    diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
    index 5ebd3c7..79c79f3 100644
    --- a/core/res/res/values-zh-rCN/strings.xml
    +++ b/core/res/res/values-zh-rCN/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允许该应用修改对于各应用的网络使用情况的统计方式。普通应用不应使用此权限。"</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"查看通知"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"文字操作"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"存储空间不足"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"某些系统功能可能无法正常使用"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正在运行"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"触摸即可了解详情或停止应用。"</string>
         <string name="ok" msgid="5970060430562524910">"确定"</string>
         <string name="cancel" msgid="6442560571259935130">"取消"</string>
         <string name="yes" msgid="5362982303337969312">"确定"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"辅助功能"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN 已激活"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
         <string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"导航首页"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"向上导航"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"更多选项"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s:%2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s - %2$s:%3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"内存设备"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD 卡"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB 存储器"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"错误"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"此应用不支持受限用户的帐户"</string>
         <string name="app_not_found" msgid="3429141853498927379">"找不到可处理此操作的应用"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"撤消"</string>
     </resources>
    
    diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
    index a0c8c05..dfd91a4 100644
    --- a/core/res/res/values-zh-rTW/strings.xml
    +++ b/core/res/res/values-zh-rTW/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允許應用程式修改應用程式網路使用量的計算方式 (不建議一般應用程式使用)。"</string>
         <string name="permlab_accessNotifications" msgid="7673416487873432268">"存取通知"</string>
         <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
    +    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (一般應用程式不需使用)。"</string>
         <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
         <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
         <string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"文字動作"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」目前正在執行"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"輕觸即可瞭解詳情或停止應用程式。"</string>
         <string name="ok" msgid="5970060430562524910">"確定"</string>
         <string name="cancel" msgid="6442560571259935130">"取消"</string>
         <string name="yes" msgid="5362982303337969312">"確定"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"協助工具"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
         <string name="vpn_title" msgid="19615213552042827">"VPN 已啟用"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
         <string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網路。"</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"瀏覽首頁"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"向上瀏覽"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"更多選項"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s:%2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s - %2$s:%3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"內部儲存空間"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"SD 卡"</string>
         <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"錯誤"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"這個應用程式不支援受限的使用者帳戶。"</string>
         <string name="app_not_found" msgid="3429141853498927379">"找不到支援此操作的應用程式"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"撤銷"</string>
     </resources>
    
    diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
    index 7f62603..41ac207 100644
    --- a/core/res/res/values-zu/strings.xml
    +++ b/core/res/res/values-zu/strings.xml
    
    @@ -621,10 +621,8 @@
         <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela insiza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinsiza ezijwayelekile."</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>
    -    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
    -    <skip />
    -    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
    -    <skip />
    +    <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>
         <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>
    @@ -1052,10 +1050,8 @@
         <string name="editTextMenuTitle" msgid="4909135564941815494">"Izenzo zombhalo"</string>
         <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Isikhala sokulondoloza siyaphela"</string>
         <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Eminye imisebenzi yohlelo ingahle ingasebenzi"</string>
    -    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
    -    <skip />
    -    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
    -    <skip />
    +    <string name="app_running_notification_title" msgid="8718335121060787914">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> iyasebenza"</string>
    +    <string name="app_running_notification_text" msgid="4653586947747330058">"Thinta ukuthola ulwazi oluningi noma ukumisa uhlelo lokusebenza."</string>
         <string name="ok" msgid="5970060430562524910">"KULUNGILE"</string>
         <string name="cancel" msgid="6442560571259935130">"Khansela"</string>
         <string name="yes" msgid="5362982303337969312">"KULUNGILE"</string>
    @@ -1273,8 +1269,7 @@
         <string name="accessibility_binding_label" msgid="4148120742096474641">"Ukufinyeleleka"</string>
         <string name="wallpaper_binding_label" msgid="1240087844304687662">"Iphephadonga"</string>
         <string name="chooser_wallpaper" msgid="7873476199295190279">"Shintsha iphephadonga"</string>
    -    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
    -    <skip />
    +    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Umlaleli wesaziso"</string>
         <string name="vpn_title" msgid="19615213552042827">"I-VPN isiyasebenza"</string>
         <string name="vpn_title_long" msgid="6400714798049252294">"i-VPN ivuswe ngu <xliff:g id="APP">%s</xliff:g>"</string>
         <string name="vpn_text" msgid="3011306607126450322">"Thinta ukuze wengamele inethiwekhi."</string>
    @@ -1378,10 +1373,8 @@
         <string name="action_bar_home_description" msgid="5293600496601490216">"Zulazulela ekhaya"</string>
         <string name="action_bar_up_description" msgid="2237496562952152589">"Zulazulela phezulu"</string>
         <string name="action_menu_overflow_description" msgid="2295659037509008453">"Izinketho ezingaphezulu"</string>
    -    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
    -    <skip />
    -    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
    -    <skip />
    +    <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
    +    <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
         <string name="storage_internal" msgid="4891916833657929263">"Isitoreji sangaphakathi"</string>
         <string name="storage_sd_card" msgid="3282948861378286745">"Ikhadi le-SD"</string>
         <string name="storage_usb" msgid="3017954059538517278">"Isitoreji se-USB"</string>
    @@ -1491,6 +1484,5 @@
         <string name="error_message_title" msgid="4510373083082500195">"Iphutha"</string>
         <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Lolu hlelo lokusebenza alusekeli ama-akhawunti wabasebenzisi abakhawulelwe"</string>
         <string name="app_not_found" msgid="3429141853498927379">"Alukho uhlelo lokusebenza olutholakele lokuphatha lesi senzo"</string>
    -    <!-- no translation found for revoke (5404479185228271586) -->
    -    <skip />
    +    <string name="revoke" msgid="5404479185228271586">"Chitha"</string>
     </resources>
    
    diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
    index 7f5a3dc..f2c0aa0 100644
    --- a/core/res/res/values/attrs_manifest.xml
    +++ b/core/res/res/values/attrs_manifest.xml
    
    @@ -909,8 +909,13 @@
             <!-- Declare that this application requires access to restricted accounts of a certain
                  type. The default value is null and restricted accounts won\'t be visible to this
                  application. The type should correspond to the account authenticator type, such as
    -             "com.google" -->
    +             "com.google". -->
             <attr name="restrictedAccountType" format="string"/>
    +        <!-- Declare that this application requires an account of a certain
    +             type. The default value is null and indicates that the application can work without
    +             any accounts. The type should correspond to the account authenticator type, such as
    +             "com.google". -->
    +        <attr name="requiredAccountType" format="string"/>
         </declare-styleable>
         
         <!-- The <code>permission</code> tag declares a security permission that can be
    
    diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
    index 42d692f..074d91f 100644
    --- a/core/res/res/values/public.xml
    +++ b/core/res/res/values/public.xml
    
    @@ -2042,6 +2042,7 @@
       <public type="attr" name="childIndicatorStart" />
       <public type="attr" name="childIndicatorEnd" />
       <public type="attr" name="restrictedAccountType" />
    +  <public type="attr" name="requiredAccountType" />
     
       <public type="style" name="Theme.NoTitleBar.Overscan" />
       <public type="style" name="Theme.Light.NoTitleBar.Overscan" />
    
    diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
    index a0e1603..3361ab7 100644
    --- a/core/res/res/values/strings.xml
    +++ b/core/res/res/values/strings.xml
    
    @@ -2411,9 +2411,14 @@
         <string name="js_dialog_title">The page at \"<xliff:g id="title">%s</xliff:g>\" says:</string>
         <!-- Default title for a javascript dialog -->
         <string name="js_dialog_title_default">JavaScript</string>
    -    <!-- Message in a javascript dialog asking if the user wishes to leave the
    -             current page -->
    -    <string name="js_dialog_before_unload">Navigate away from this page?\n\n<xliff:g id="message">%s</xliff:g>\n\nTouch OK to continue, or Cancel to stay on the current page.</string>
    +    <!-- Title for the unload javascript dialog -->
    +    <string name="js_dialog_before_unload_title">Confirm Navigation</string>
    +    <!-- Text for the positive button on the unload javascript dialog -->
    +    <string name="js_dialog_before_unload_positive_button">Leave this Page</string>
    +    <!-- Text for the negative button on the unload javascript dialog -->
    +    <string name="js_dialog_before_unload_negative_button">Stay on this Page</string>
    +    <!-- Message in a javascript dialog asking if the user wishes to leave the current page -->
    +    <string name="js_dialog_before_unload"><xliff:g id="message">%s</xliff:g>\n\nAre you sure you want to navigate away from this page?</string>
     
         <!-- Title of the WebView save password dialog.  If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. -->
         <string name="save_password_label">Confirm</string>
    
    diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
    index e06bcd1..45ea182 100644
    --- a/core/res/res/values/symbols.xml
    +++ b/core/res/res/values/symbols.xml
    
    @@ -549,6 +549,9 @@
       <java-symbol type="string" name="ime_action_search" />
       <java-symbol type="string" name="ime_action_send" />
       <java-symbol type="string" name="invalidPin" />
    +  <java-symbol type="string" name="js_dialog_before_unload_positive_button" />
    +  <java-symbol type="string" name="js_dialog_before_unload_negative_button" />
    +  <java-symbol type="string" name="js_dialog_before_unload_title" />
       <java-symbol type="string" name="js_dialog_before_unload" />
       <java-symbol type="string" name="js_dialog_title" />
       <java-symbol type="string" name="js_dialog_title_default" />
    
    diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
    index 2ca77dd..3e3b12d0 100644
    --- a/docs/html/_redirects.yaml
    +++ b/docs/html/_redirects.yaml
    
    @@ -24,6 +24,9 @@
     - from: /sdk/installing/next.html
       to: /training/basics/firstapp/index.html
     
    +- from: /sdk/ndk/overview.html
    +  to: /tools/sdk/ndk/index.html
    +
     - from: /sdk/ndk/...
       to: /tools/sdk/ndk/...
     
    @@ -113,13 +116,14 @@
     - from: /guide/appendix/install-location.html
       to: /guide/topics/data/install-location.html
     
    -- from: /guide/basics/what-is-android.html
    +- from: /guide/basics/...
       to: /about/index.html
     
     - from: /guide/topics/security/security.html
       to: /training/articles/security-tips.html
    -#  type: permanent
    -#  comment: Move content and then adjust this
    +
    +- from: /guide/topics/security/index.html
    +  to: /training/articles/security-tips.html
     
     - from: /guide/appendix/market-filters.html
       to: /google/play/filters.html
    
    diff --git a/docs/html/design/building-blocks/buttons.jd b/docs/html/design/building-blocks/buttons.jd
    index 9e82ed4..600ec6c5 100644
    --- a/docs/html/design/building-blocks/buttons.jd
    +++ b/docs/html/design/building-blocks/buttons.jd
    
    @@ -1,5 +1,5 @@
     page.title=Buttons
    -page.tags="button"
    +page.tags="button","input"
     @jd:body
     
     <p>A button consists of text and/or an image that clearly communicates what action will occur when the
    
    diff --git a/docs/html/design/building-blocks/grid-lists.jd b/docs/html/design/building-blocks/grid-lists.jd
    index 69a43b1..8c82ba9 100644
    --- a/docs/html/design/building-blocks/grid-lists.jd
    +++ b/docs/html/design/building-blocks/grid-lists.jd
    
    @@ -1,5 +1,5 @@
     page.title=Grid Lists
    -page.tags="gridview","layout"
    +page.tags="gridview","layout","listview"
     @jd:body
     
     <img src="{@docRoot}design/media/gridview_overview.png">
    
    diff --git a/docs/html/design/building-blocks/progress.jd b/docs/html/design/building-blocks/progress.jd
    index 96cc1af..60ad2ca 100644
    --- a/docs/html/design/building-blocks/progress.jd
    +++ b/docs/html/design/building-blocks/progress.jd
    
    @@ -1,5 +1,5 @@
     page.title=Progress &amp; Activity
    -page.tags="progressbar"
    +page.tags="progressbar","download","network"
     @jd:body
     
     <p>Progress bars and activity indicators signal to users that something is happening that will take a moment.</p>
    
    diff --git a/docs/html/design/building-blocks/spinners.jd b/docs/html/design/building-blocks/spinners.jd
    index 8c80b91..3550b0c 100644
    --- a/docs/html/design/building-blocks/spinners.jd
    +++ b/docs/html/design/building-blocks/spinners.jd
    
    @@ -1,5 +1,5 @@
     page.title=Spinners
    -page.tags="spinner","drop down"
    +page.tags="spinner","dropdown"
     @jd:body
     
     <p>Spinners provide a quick way to select one value from a set. In the default state, a spinner shows
    
    diff --git a/docs/html/design/building-blocks/switches.jd b/docs/html/design/building-blocks/switches.jd
    index 6386bdf..0b195b9 100644
    --- a/docs/html/design/building-blocks/switches.jd
    +++ b/docs/html/design/building-blocks/switches.jd
    
    @@ -1,5 +1,5 @@
     page.title=Switches
    -page.tags="switch","checkbox","radiobutton"
    +page.tags="switch","checkbox","radiobutton","button"
     @jd:body
     
     <p>Switches allow the user to select options. There are three kinds of switches: checkboxes, radio
    
    diff --git a/docs/html/design/building-blocks/tabs.jd b/docs/html/design/building-blocks/tabs.jd
    index 1fe2c62..79cc9c7 100644
    --- a/docs/html/design/building-blocks/tabs.jd
    +++ b/docs/html/design/building-blocks/tabs.jd
    
    @@ -1,5 +1,5 @@
     page.title=Tabs
    -page.tags="tabs","action bar","navigation"
    +page.tags="tabs","actionbar","navigation","viewpager"
     @jd:body
     
     <img src="{@docRoot}design/media/tabs_overview.png">
    
    diff --git a/docs/html/design/building-blocks/text-fields.jd b/docs/html/design/building-blocks/text-fields.jd
    index c1bed78..82321f0 100644
    --- a/docs/html/design/building-blocks/text-fields.jd
    +++ b/docs/html/design/building-blocks/text-fields.jd
    
    @@ -1,5 +1,5 @@
     page.title=Text Fields
    -page.tags="text","edittext","input",
    +page.tags="text","edittext","input"
     @jd:body
     
     <p>Text fields allow the user to type text into your app. They can be either single line or multi-line.
    
    diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
    index edf3843..5f46082 100644
    --- a/docs/html/design/patterns/accessibility.jd
    +++ b/docs/html/design/patterns/accessibility.jd
    
    @@ -1,5 +1,5 @@
     page.title=Accessibility
    -page.tags="accessibility","navigation"
    +page.tags="accessibility","navigation","input"
     @jd:body
     
     <p>One of Android's missions is to organize the world's information and make it universally accessible and useful. Accessibility is the measure of how successfully a product can be used by people with varying abilities. Our mission applies to all users-including people with disabilities such as visual impairment, color deficiency, hearing loss, and limited dexterity.</p>
    
    diff --git a/docs/html/design/patterns/app-structure.jd b/docs/html/design/patterns/app-structure.jd
    index e1bb819..1809ecd 100644
    --- a/docs/html/design/patterns/app-structure.jd
    +++ b/docs/html/design/patterns/app-structure.jd
    
    @@ -1,5 +1,5 @@
     page.title=Application Structure
    -page.tags="navigation","layout"
    +page.tags="navigation","layout","tablet"
     @jd:body
     
     <p>Apps come in many varieties that address very different needs. For example:</p>
    
    diff --git a/docs/html/design/patterns/compatibility.jd b/docs/html/design/patterns/compatibility.jd
    index 84ae337..3a56f52 100644
    --- a/docs/html/design/patterns/compatibility.jd
    +++ b/docs/html/design/patterns/compatibility.jd
    
    @@ -1,4 +1,5 @@
     page.title=Backwards Compatibility
    +page.tags="support"
     @jd:body
     
     <p>Significant changes in Android 3.0 included:</p>
    
    diff --git a/docs/html/design/patterns/confirming-acknowledging.jd b/docs/html/design/patterns/confirming-acknowledging.jd
    index f2e88ec..e347231 100644
    --- a/docs/html/design/patterns/confirming-acknowledging.jd
    +++ b/docs/html/design/patterns/confirming-acknowledging.jd
    
    @@ -1,5 +1,5 @@
     page.title=Confirming &amp; Acknowledging
    -page.tags="dialog","toast"
    +page.tags="dialog","toast","notification"
     @jd:body
     
     <p>In some situations, when a user invokes an action in your app, it's a good idea to <em>confirm</em> or <em>acknowledge</em> that action through text.</p>
    
    diff --git a/docs/html/design/patterns/gestures.jd b/docs/html/design/patterns/gestures.jd
    index 3ef133d..127a1c8 100644
    --- a/docs/html/design/patterns/gestures.jd
    +++ b/docs/html/design/patterns/gestures.jd
    
    @@ -1,5 +1,5 @@
     page.title=Gestures
    -page.tags="gesture","input"
    +page.tags="gesture","input","touch"
     @jd:body
     
     <p>Gestures allow users to interact with your app by manipulating the screen objects you provide. The
    
    diff --git a/docs/html/design/patterns/help.jd b/docs/html/design/patterns/help.jd
    index cdac54d..a32fb25 100644
    --- a/docs/html/design/patterns/help.jd
    +++ b/docs/html/design/patterns/help.jd
    
    @@ -1,4 +1,5 @@
     page.title=Help
    +page.tags="settings","preferences"
     @jd:body
     
     <p>We wish we could guarantee that if you follow every piece of advice on this website, everyone will be able to learn and use your app without a hitch. Sadly, that's not the case.</p>
    
    diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
    index 36debbe..b717884 100644
    --- a/docs/html/design/patterns/navigation.jd
    +++ b/docs/html/design/patterns/navigation.jd
    
    @@ -1,5 +1,5 @@
     page.title=Navigation with Back and Up
    -page.tags="navigation","activity"
    +page.tags="navigation","activity","task"
     @jd:body
     
     <p>Consistent navigation is an essential component of the overall user experience. Few things frustrate
    
    diff --git a/docs/html/design/patterns/selection.jd b/docs/html/design/patterns/selection.jd
    index 682ce56..d16e86c 100644
    --- a/docs/html/design/patterns/selection.jd
    +++ b/docs/html/design/patterns/selection.jd
    
    @@ -1,5 +1,5 @@
     page.title=Selection
    -page.tags="actionmode","navigation"
    +page.tags="actionmode","navigation","contextual"
     @jd:body
     
     <p>Android 3.0 changed the <em>long press</em> gesture&mdash;that is, a touch that's held in the same position for a moment&mdash;to be the global gesture to select data.. This affects the way you should
    
    diff --git a/docs/html/design/patterns/settings.jd b/docs/html/design/patterns/settings.jd
    index f86cd39..4748e48 100644
    --- a/docs/html/design/patterns/settings.jd
    +++ b/docs/html/design/patterns/settings.jd
    
    @@ -1,5 +1,5 @@
     page.title=Settings
    -page.tags="settings","preferences"
    +page.tags="preferences","sharedpreferences"
     @jd:body
     
     <p>Settings is a place in your app where users indicate their preferences for how your app should
    
    diff --git a/docs/html/design/patterns/swipe-views.jd b/docs/html/design/patterns/swipe-views.jd
    index b86d990..f18fc63 100644
    --- a/docs/html/design/patterns/swipe-views.jd
    +++ b/docs/html/design/patterns/swipe-views.jd
    
    @@ -1,5 +1,5 @@
     page.title=Swipe Views
    -page.tags="viewpager","navigation"
    +page.tags="viewpager","navigation","tabs"
     @jd:body
     
     <p>Efficient navigation is one of the cornerstones of a well-designed app. While apps are generally
    
    diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
    index f2b0f4a..3152e91 100644
    --- a/docs/html/design/patterns/widgets.jd
    +++ b/docs/html/design/patterns/widgets.jd
    
    @@ -1,5 +1,5 @@
     page.title=Widgets
    -page.tags="appwidget"
    +page.tags="appwidget","home"
     @jd:body
     
     <p>Widgets are an essential aspect of home screen customization. You can imagine them as "at-a-glance" views of an app's most important data and functionality that is accessible right from the user's home screen. Users can move widgets across their home screen panels, and, if supported, resize them to tailor the amount of information within a widget to their preference.</p>
    
    diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd
    index ce11cf7..1475e5c 100644
    --- a/docs/html/design/style/iconography.jd
    +++ b/docs/html/design/style/iconography.jd
    
    @@ -1,4 +1,5 @@
     page.title=Iconography
    +page.tags="icons"
     @jd:body
     
     <img src="{@docRoot}design/media/iconography_overview.png">
    
    diff --git a/docs/html/design/style/metrics-grids.jd b/docs/html/design/style/metrics-grids.jd
    index e2b9ab5..3116ff6d 100644
    --- a/docs/html/design/style/metrics-grids.jd
    +++ b/docs/html/design/style/metrics-grids.jd
    
    @@ -1,4 +1,5 @@
     page.title=Metrics and Grids
    +page.tags="layout","screens"
     @jd:body
     
     <p>Devices vary not only in physical size, but also in screen density (<acronym title="Dots per
    
    diff --git a/docs/html/design/style/touch-feedback.jd b/docs/html/design/style/touch-feedback.jd
    index 5fe72a7..340a3a4 100644
    --- a/docs/html/design/style/touch-feedback.jd
    +++ b/docs/html/design/style/touch-feedback.jd
    
    @@ -1,4 +1,5 @@
     page.title=Touch Feedback
    +page.tags="input","button"
     @jd:body
     
     <div class="layout-content-row" style="margin-bottom: -100px">
    
    diff --git a/docs/html/design/style/typography.jd b/docs/html/design/style/typography.jd
    index 427b8c6..114d13b 100644
    --- a/docs/html/design/style/typography.jd
    +++ b/docs/html/design/style/typography.jd
    
    @@ -1,4 +1,5 @@
     page.title=Typography
    +page.tags="textview","font"
     @jd:body
     
     <div class="layout-content-row">
    
    diff --git a/docs/html/design/style/writing.jd b/docs/html/design/style/writing.jd
    index 919ea7aa..5358847 100644
    --- a/docs/html/design/style/writing.jd
    +++ b/docs/html/design/style/writing.jd
    
    @@ -1,4 +1,5 @@
     page.title=Writing Style
    +page.tags="dialog","toast","notification"
     @jd:body
     
     <p>When choosing words for your app:</p>
    
    diff --git a/docs/html/distribute/distribute_toc.cs b/docs/html/distribute/distribute_toc.cs
    index ad3121c..3ea11bf 100644
    --- a/docs/html/distribute/distribute_toc.cs
    +++ b/docs/html/distribute/distribute_toc.cs
    
    @@ -1,106 +1,71 @@
     <ul id="nav">
     
       <li class="nav-section">
    -    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/index.html">
    -      <span class="en">Google Play</span></a>
    -    </div>
    +    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/index.html">Google Play</a></div>
         <ul>
    -      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/visibility.html">
    -           <span class="en">Visibility</a></li>
    -      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/monetizing.html">
    -           <span class="en">Monetizing</a></li>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/about/distribution.html">
    -           <span class="en">Distribution</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/visibility.html">Visibility</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/monetizing.html">Monetizing</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/distribution.html">Distribution</a></li>
         </ul>  
       </li>
     
       <li class="nav-section">
    -    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/publish/index.html">
    -      <span class="en">Publishing</span></a>
    -    </div>
    +    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/publish/index.html">Publishing</a></div>
         <ul>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/register.html">
    -           <span class="en">Get Started</span>
    -          </a></li>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/console.html">
    -           <span class="en">Developer Console</span>
    -          </a></li>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/preparing.html">
    -           <span class="en">Publishing Checklist</span>
    -          </a></li>
    -
    -     </ul>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/register.html">Get Started</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/console.html">Developer Console</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/preparing.html">Publishing Checklist</a></li>
    +    </ul>
       </li>
       
     <!--  <li class="nav-section">
    -    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/developer-console.html">
    -        <span class="en">The Developer Console</span>
    -      </a>
    +    <div class="nav-section-header">
    +      <a href="<?cs var:toroot ?>distribute/googleplay/developer-console.html">The Developer Console</a>
         </div>
         <ul>
    -      <li class="nav-section"><a href="<?cs var:toroot ?>distribute/googleplay/register.html">
    -        <span class="en">Get Started</span></a></li>
    -      <li><a href="<?cs var:toroot ?>distribute/googleplay/distribution-controls.html">
    -        <span class="en">Managing Distribution</span>
    -        </a></li>
    -      <li><a href="<?cs var:toroot ?>distribute/googleplay/pricing-billing.html">
    -        <span class="en">Pricing and Billing</span>
    -        </a></li>
    -      <li><a href="<?cs var:toroot ?>distribute/googleplay/app-data.html">
    -        <span class="en">Reviewing App Data</span>
    -        </a></li>
    -      <li><a href="<?cs var:toroot ?>distribute/googleplay/advanced-options.html">
    -        <span class="en">Advanced Options</span>
    -        </a></li>
    -      <li><a href="<?cs var:toroot ?>distribute/googleplay/publishing.html">
    -        <span class="en">Publishing and Updating</span>
    -        </a></li>
    +      <li class="nav-section"><a href="<?cs var:toroot ?>distribute/googleplay/register.html">Get Started</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/distribution-controls.html">Managing Distribution</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/pricing-billing.html">Pricing and Billing</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/app-data.html">Reviewing App Data</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/advanced-options.html">Advanced Options</a></li>
    +      <li><a href="<?cs var:toroot ?>distribute/googleplay/publishing.html">Publishing and Updating</a></li>
         </ul>
       </li> end of Developer Console -->
    -  
    +
        <li class="nav-section">
    -     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/promote/index.html">
    -       <span class="en">Promoting</span></a>
    +     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/promote/index.html">Promoting</a>
          </div>
          <ul>
    -<!--   <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/product-pages.html">
    -        <span class="en">Your Product Pages</a></li> 
    --->
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/linking.html">
    -        <span class="en">Linking to Your Products</a></li>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/badges.html">
    -        <span class="en">Google Play Badges</a></li>
    -       <li><a href="<?cs var:toroot ?>distribute/promote/device-art.html">
    -        <span class="en">Device Art Generator</a></li>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/brand.html">
    -        <span class="en">Brand Guidelines</a></li>
    +<!--   <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/product-pages.html">Your Product Pages</a></li> -->
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/linking.html">Linking to Your Products</a></li>
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/badges.html">Google Play Badges</a></li>
    +       <li><a href="<?cs var:toroot ?>distribute/promote/device-art.html">Device Art Generator</a></li>
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/brand.html">Brand Guidelines</a></li>
          </ul>
        </li>
     
    -
       <li class="nav-section">
    -    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">
    -      <span class="en">App Quality</span></a>
    -    </div>
    +    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">App Quality</a></div>
         <ul>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/core.html">
    -          <span class="en">Core App Quality</span>
    -         </a></li>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/tablet.html">
    -          <span class="en">Tablet App Quality</span>
    -         </a></li>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">
    -          <span class="en">Improving App Quality</span>
    -         </a></li>
    -
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/core.html">Core App Quality</a></li>
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/tablet.html">Tablet App Quality</a></li>
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
         </ul>
       </li> 
     
    +   <li class="nav-section">
    +     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/policies/index.html">Policies</a></div>
    +     <ul>
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/spam.html">Spam</a></li>
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ip.html">Intellectual<br />Property</a></li> 
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ads.html">Ads</a></li>
    +     </ul>
    +   </li>
     
     <!--    
        <li class="nav-section">
         <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/after.html">
    -      <span class="en">After Launch</span></a>
    +      After Launch</a>
         </div>
         <ul>
            <li><a href="<?cs var:toroot ?>distribute/googleplay/errors.html.html">Reviewing Errors</a></li>
    @@ -111,22 +76,14 @@
     -->
     
       <li class="nav-section">
    -    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">
    -      <span class="en">Spotlight</span></a>
    -    </div>
    +    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">Spotlight</a></div>
         <ul>
    -       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">
    -          <span class="en">Tablet Stories</span>
    -         </a></li>
    +       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">Tablet Stories</a></li>
         </ul>
       </li> 
     
       <li class="nav-section">
    -    <div class="nav-section-header empty">
    -      <a href="<?cs var:toroot ?>distribute/open.html">
    -        <span class="en">Open Distribution</span>
    -      </a>
    -    </div>
    +    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>distribute/open.html">Open Distribution</a></div>
       </li>
     </ul>
       
    \ No newline at end of file
    
    diff --git a/docs/html/distribute/googleplay/policies/ads.jd b/docs/html/distribute/googleplay/policies/ads.jd
    new file mode 100644
    index 0000000..8920499
    --- /dev/null
    +++ b/docs/html/distribute/googleplay/policies/ads.jd
    
    @@ -0,0 +1,352 @@
    +page.title=Ads
    +@jd:body
    +
    +<div id="qv-wrapper">
    +<div id="qv">
    +  <h2>In This Document</h2>
    +  <ol>
    +    <li><a href="#content-maturity">Content and Maturity</a></li>
    +    <li><a href="#context">Context and Behavior</a></li>
    +    <li><a href="#disclosure" style="clear:right">Disclosure</a></li>
    +    <li><a href="#impersonation">Impersonation of System UI</a></li>
    +    <li><a href="#adwalls">Adwalls</a></li>
    +    <li><a href="#interfering" style="clear:right;">Interference with Ads and Websites</a></li>
    +  </ol>
    +
    +  <h2>More Resources</h2>
    +  <ol>
    +    <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
    +    <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages" target="_policies">Developer Distribution Agreement</a></li>
    +    <li><a href="http://support.google.com/googleplay/android-developer/answer/188189" target="_policies">Maturity Ratings</a></p>
    +  </ol>
    +</div>
    +</div>
    +
    +<p>
    +  Google Play policies guide how you can use ads in your apps, to help ensure
    +  the best experience for users visiting and downloading apps from the store.
    +</p>
    +
    +<p>
    +  In general, for the purposes of policy, the content of ads displayed by your
    +  app is considered part of your app. As an app developer, it is your
    +  responsibility to ensure that the content, context, and behavior of ads in
    +  your apps conforms to Google Play policies.
    +</p>
    +
    +<p>
    +  Before you publish, make sure you understand Google Play ad policies and how
    +  to display ads in conformance with those policies. The sections below
    +  highlight best practices and common examples to help you avoid the most
    +  common types of policy violations.
    +</p>
    +
    +<p>
    +  For more information about Google Play policies that apply to your apps and
    +  content, please see the <a href=
    +  "http://play.google.com/about/developer-content-policy.html" target=
    +  "_policies">Developer Program Policies</a> and <a href=
    +  "http://play.google.com/about/developer-distribution-agreement.html" target=
    +  "_policies">Developer Distribution Agreement</a>.
    +</p>
    +
    +
    +<h2 id="content-maturity">Content and Maturity</h2>
    +
    +<div class="example-block bad">
    +  <div class="heading">Ad maturity exceeds app</div>
    +  <img src="{@docRoot}images/gp-policy-ads-maturity-violation.png">
    +</div>
    +
    +<p>
    +  From a policy perspective, ads shown in your app are part of your content
    +  and your app is responsible for any violations. If an ad shown in your app
    +  violates Google Play policies, your app may be suspended or your developer
    +  account terminated.
    +</p>
    +
    +<p>
    +  For this reason, it's important for you to be be aware of what ads will be
    +  displayed in your app and to manage the ads content according to Google Play
    +  policies. Here are some guidelines:
    +</p>
    +
    +<ul>
    +    <li>
    +        <strong>Ads must not violate Content Policy</strong>&mdash;Ads in
    +        your app must not violate the terms of Google Play’s Content Policy,
    +        including those concerning illegal activities, violence, sexually
    +        explicit content, or privacy violations.
    +    </li>
    +    <li>
    +        <strong>Ads maturity must be consistent with your app's
    +        maturity</strong>&mdash;Content shown in your ads must be consistent
    +        with the app’s maturity rating in Google Play. Especially, ads content
    +        should never exceed your app's maturity rating, even if the ads content
    +        by itself complies with general policies.
    +    </li>
    +</ul>
    +
    +<p>
    +  In the example at right, the app's maturity rating is set to
    +  "Everyone", which is the lowest maturity level on Google Play. By choosing
    +  the "Everyone" maturity level, the developer is declaring that all of the
    +  content in the app, <em>including ads</em>, is suitable for all users
    +  regardless of age.
    +</p>
    +
    +<p>
    +  The example app violates Google Play policies by displaying ad content with a
    +  higher maturity level&mdash;ad content showing gambling, profanity, user
    +  location, suggestive content, or content from another app with higher
    +  maturity exceeds the "Everyone" maturity rating. Because the ad's
    +  maturity is higher than the app's maturity level, the app itself is in
    +  violation of policy. To correct the problem, the developer must either
    +  restrict ads content to "Everyone" level or raise the app's maturity rating.
    +</p>
    +
    +<p>
    +  For detailed information about how to choose the appropriate maturity level
    +  for your app, or to assess the maturity requirement of ads in your app, see
    +  <a href=
    +  "http://support.google.com/googleplay/android-developer/answer/188189"
    +  target="_policies">Rating your application content for Google Play</a>.
    +</p>
    +
    +
    +<h2 id="context">Context and Behavior</h2>
    +
    +<p>
    +  If your app displays ads, it should do so in ways that do not interrupt users,
    +  mislead them into clicking on ads, or make changes outside the app without
    +  the user's knowledge or consent. Here are some guidelines:
    +</p>
    +
    +<ul>
    +  <li>
    +    <strong>Display your ads within your UI</strong>&mdash;If possible,
    +    display ads only within your app's UI. This leads to a better user
    +    experience and helps avoid policy violations
    +  </li>
    +
    +  <li>
    +    <strong>Make sure app origin is clear</strong>&mdash;When you display an
    +    ad, it must be clear to the user that the ad has originated from your app.
    +    If you show the ad in your app's UI while your app has focus, the user
    +    understands the ad origin without explicit attribution. However, if you
    +    display the ad outside of your app, such as in a notification, you must
    +    explicitly indicate the origin.
    +  </li>
    +
    +  <li>
    +    <strong>Don't make changes outside of the app without consent</strong>
    +   &mdash;Ads must not make changes outside of the app without the user's
    +    full knowledge and consent. For example, ads should not install shortcuts,
    +    bookmarks, or icons, or change default settings without user consent.
    +  </li>
    +
    +  <li>
    +    <strong>Changes outside the app must be reversible</strong>&mdash;If an
    +    ad makes changes outside the app as described above, the changes (and
    +    origin app) must be evident and easily reversible. For example, the user
    +    must be able to locate and reverse the changes by adjusting settings,
    +    changing ad preferences in the app, or uninstalling the app altogether.
    +  </li>
    +
    +  <li>
    +    <strong>Notification ads require user opt-in</strong>&mdash;Your app
    +    should not create <a href=
    +    "{@docRoot}design/patterns/notifications.html">notifications</a>
    +    containing ads unless the user has specifically opted-in to this behavior
    +    and is able to easily opt-out.
    +  </li>
    +
    +  <li>
    +    <strong>Use low priority for notification ads</strong>&mdash;Always
    +    assign your notification ads <a href="
    +    {@docRoot}reference/android/app/Notification.html#PRIORITY_LOW">low
    +    priority</a> (for API level 16 and above).
    +  </li>
    +</ul>
    +
    +<div class="example-block bad" style="width:400px;margin:.5em 0 0 2em;">
    +    <div class="heading">Does not fully indicate origin app</div>
    +    <img src="{@docRoot}images/gp-policy-ads-notif-attr-violation.png">
    +</div>
    +<div class="example-block good" style="width:400px;margin:.5em 0 0 2em;">
    +    <div class="heading">Indicates origin app by name and icon</div>
    +    <img src="{@docRoot}images/gp-policy-ads-notif-attr.png">
    +</div>
    +
    +<p>
    +  In particular, note that notification ads must clearly identify your app as
    +  the ad origin. If your app sends notification ads that do not sufficiently
    +  identify your app as the origin, the app will be in violation of policy.
    +</p>
    +
    +<p>
    +  To identify your app as the origin, you should display the <strong>app's full
    +  name and and icon</strong> in the notification to provide the clearest
    +  identification and best policy compliance. Displaying a partial app name can
    +  also be sufficient, provided the name unambiguously identifies your app.
    +</p>
    +
    +<p>
    +  Above right is an example notification ad that violates ad policy by not
    +  providing attribution of the origin app. Below right, the notification ads
    +  comply with policy by providing both the app icon and full app name (in this
    +  case, "Turtle Test").
    +</p>
    +
    +
    +<h2 id="disclosure" style="clear:right">Disclosure of Ads to Users</h2>
    +
    +<p>
    +  It's important to sufficiently disclose to users how your app will use ads.
    +  You must make it easy for users to understand what ads will be shown in your
    +  app, where they will be shown, and what the associated behaviors are, if any.
    +  Further, you should ask for user consent and provide options for managing ads
    +  or opt-out. Here are some guidelines:
    +</p>
    +
    +<ul>
    +  <li>
    +    <strong>Tell users about your ads</strong>&mdash;Create a simple,
    +    complete disclosure that tells users how your app uses ads, where the ads
    +    are shown, and how they can manage ad options. Take common-sense steps to
    +    make the disclosure as clear as possible.
    +  </li>
    +
    +  <li>
    +    <strong>Make sure users know</strong>&mdash;Present your ads disclosure
    +    is an easy-to-see location, rather than hiding it where users are not
    +    likely to find it.
    +  </li>
    +
    +  <li>
    +    <strong>Ask for consent (opt-in) at launch</strong>&mdash;Where possible,
    +    include your ads disclosure in the app description as well as in an Ads
    +    Terms, End User License Agreement (EULA), or similar document. Display the
    +    terms at first launch and ask for the user's consent before continuing to
    +    the app.
    +  </li>
    +</ul>
    +
    +<p>
    +  A recommended approach is to provide an ads disclosure in an End-User License
    +  Agreement (EULA). The disclosure should be clear and succinct and displayed
    +  in a modal dialog that asks the user to agree to the terms before using the
    +  app.
    +</p>
    +
    +<p>
    +  If your app adds homescreen icons and/or browser bookmarks, an acceptable
    +  practice for revealing that behavior is to provide a disclosure in both the
    +  app description and an opt-in EULA on app launch. This ensures that the
    +  behaviors are clearly explained to the user up-front and requires the user’s
    +  consent in a pop-up EULA to continue using the app.
    +</p>
    +
    +<div class="example-block good" style="width:213px;margin-right:2em;">
    +  <div class="heading">Disclosure in Terms</div>
    +  <img src="{@docRoot}images/gp-policy-ads-terms.png">
    +</div>
    +
    +<div class="example-block good" style="width:213px;">
    +  <div class="heading">Disclosure in EULA</div>
    +  <img src="{@docRoot}images/gp-policy-ads-eula.png">
    +</div>
    +
    +<div class="example-block bad" style="width:213px;margin-left:0em;">
    +  <div class="heading">Disclosure is hidden</div>
    +  <img src="{@docRoot}images/gp-policy-ads-eula-violation.png">
    +</div>
    +
    +<p style="clear:right">
    +  Above left is an example of ads disclosure that is hidden in a long EULA. The
    +  disclosure information itself is not clearly indicated in the document text
    +  and it's not visible unless the user happens to scroll down far enough in the
    +  EULA. Above middle and right show two alternative approaches that
    +  present the disclosure in an obvious and clear manner at the top of a
    +  EULA and in a dedicated Terms agreement. 
    +</p>
    +
    +
    +<h2 id="impersonation">Impersonation of System UI</h2>
    +
    +<div class="example-block bad">
    +  <div class="heading">Ad impersonates system dialog</div>
    +  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation.png">
    +</div>
    +
    +<p>
    +  Your app must not display any ad that attempts to impersonate or represent a
    +  system function or UI component. If such an ad is displayed in your app, your
    +  app will be in violation of policy and subject to suspension. Here are some
    +  guidelines:
    +</p>
    +
    +<ul>
    +  <li>
    +    <strong>No fake system dialogs or warnings</strong>&mdash;Any ad that
    +    presents itself as a system dialog or warning and asks for user input is in
    +    violation of Google Play policies.
    +  </li>
    +
    +  <li>
    +    <strong>No fake app updates</strong>&mdash;Ads should not impersonate
    +    system UI for app updates.
    +  </li>
    +</ul>
    +
    +<p>
    +  At right is an example of a pop-up ad impersonating a system dialog, warning
    +  the user about viruses. This is a violation of policy.
    +</p>
    +
    +
    +<h2 id="adwalls">Adwalls</h2>
    +
    +<div class="example-block good" style="width:213px;">
    +  <div class="heading">Adwall lets user cancel</div>
    +  <img src="{@docRoot}images/gp-policy-ads-paywall.png">
    +</div>
    +
    +<div class="example-block bad" style="width:213px;">
    +  <div class="heading">Adwall forces user action</div>
    +  <img src="{@docRoot}images/gp-policy-ads-paywall-violation.png">
    +</div>
    +
    +<p>
    +  If your app uses adwalls to drive affiliate traffic, those adwalls must not
    +  force the user to click on ads or submit personal information for advertising
    +  purposes before using the app.
    +</p>
    +
    +<p>
    +  Forcing a user action in an adwall is not only a poor user experience, it is
    +  a violation of Google Play policies.
    +</p>
    +
    +<p>
    +  For this reason, <strong>all adwalls must give the user the option to
    +  cancel</strong> or otherwise dismiss the ad without penalty.
    +</p>
    +
    +<p>
    +  At right is an example of an app that requires the user to click through the
    +  ad to fully use the app. This is a violation of policy.
    +</p>
    +
    +<p>
    +  The adjacent example demonstrates an adequate option to let the user dismiss
    +  the ad wall easily by cancelling.
    +</p>
    +
    +
    +<h2 id="interfering" style="clear:right;">Interference with Third-party Ads and Websites</h2>
    +
    +<p>
    +  Ads associated with your app <strong>must not interfere</strong> with any
    +  other ads originating in other applications.
    +</p>
    \ No newline at end of file
    
    diff --git a/docs/html/distribute/googleplay/policies/index.jd b/docs/html/distribute/googleplay/policies/index.jd
    new file mode 100644
    index 0000000..fb46055
    --- /dev/null
    +++ b/docs/html/distribute/googleplay/policies/index.jd
    
    @@ -0,0 +1,59 @@
    +page.title=Google Play Policies and Guidelines
    +page.metaDescription=Guidelines and tips for creating apps that comply with Google Play content and distribution policies.
    +@jd:body
    +
    +<p>
    +  Before publishing your apps on Google Play, take a few minutes to read and
    +  understand the content and distribution policies that apply to all apps
    +  in the store. These policies help to keep Android and Google Play an enjoyable
    +  and trusted platform for content consumers and developers alike.
    +</p>
    +
    +<p>
    +  The documents below highlight important policy areas and provide tips to help
    +  you create policy-compliant apps. You'll also find examples and guidance on common
    +  policy questions that can help your app stay clear of practices that can result in
    +  low ratings or even suspensions from the store.
    +</p>
    +
    +<p>
    +  For complete information about Google Play policies, please see the full
    +  <a href="http://play.google.com/about/developer-content-policy.html" target=
    +  "_policies">Developer Program Policies</a> and <a href=
    +  "http://play.google.com/about/developer-distribution-agreement.html" target=
    +  "_policies">Developer Distribution Agreement</a> documents.
    +</p>
    +
    +<div class="vspace size-1">
    +  &nbsp;
    +</div>
    +<div class="layout-content-row">
    +  <div class="layout-content-col span-4">
    +    <h4>
    +      Spam
    +    </h4>
    +    <p>
    +      Make sure that your app does not present content that is unwanted,
    +      deceptive, repetitive, or unrelated to the core function of the app.
    +    </p><a href="{@docRoot}distribute/googleplay/policies/spam.html">Learn more &raquo;</a>
    +  </div>
    +  <div class="layout-content-col span-4">
    +    <h4>
    +      Intellectual Property
    +    </h4>
    +    <p>
    +      Tips and examples of how to use intelletual property (IP) properly,
    +      including when to ask permission to use someone else's copyright or
    +      trademark.
    +    </p><a href="{@docRoot}distribute/googleplay/policies/ip.html">Learn more &raquo;</a>
    +  </div>
    +  <div class="layout-content-col span-4">
    +    <h4>
    +      Ads
    +    </h4>
    +    <p>
    +      Make sure that the ads displayed in your app follow the Google Play Content
    +      Policy and meet the maturity rating that you have selected for your app.
    +    </p><a href="{@docRoot}distribute/googleplay/policies/ads.html">Learn more &raquo;</a>
    +  </div>
    +</div>
    \ No newline at end of file
    
    diff --git a/docs/html/distribute/googleplay/policies/ip.jd b/docs/html/distribute/googleplay/policies/ip.jd
    new file mode 100644
    index 0000000..0d1f68d
    --- /dev/null
    +++ b/docs/html/distribute/googleplay/policies/ip.jd
    
    @@ -0,0 +1,345 @@
    +page.title=Intellectual Property
    +@jd:body
    +
    +<div id="qv-wrapper">
    +<div id="qv">
    +  <h2>In This Document</h2>
    +  <ol>
    +    <li><a href="#copyright">Copyright Infringement</a></li>
    +    <li><a href="#impersonation">Impersonation</a></li>
    +    <li><a href="#trademarks">Trademark Infringement</a></li>
    +    <li><a href="#other">DDA 4.4 Prohibited Actions</a></li>
    +  </ol>
    +
    +  <h2>More Resources</h2>
    +  <ol>
    +    <li><a href="http://play.google.com/about/developer-content-policy.html"
    +    target="_policies">Developer Program Policies</a></li>
    +    <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages"
    +    target="_policies">Developer Distribution Agreement</a></li>
    +  </ol>
    +</div>
    +</div>
    +
    +<p>
    +  Google Play policies protect your intellectual property (IP) as well as that
    +  of other app developers and content creators in the store. The policies and
    +  their enforcements help ensure proper use of copyright, trademarks, and
    +  developer identity in Google Play.
    +</p>
    +
    +<p>
    +  As an app developer, these IP policies benefit you. At the same time, it's
    +  your responsibility to ensure that your app does not violate the IP of other
    +  developers or content creators. Violations of IP-related policy may result in
    +  suspension of your apps from the store and termination of your developer
    +  account.
    +</p>
    +
    +<p>
    +  This document introduces several key areas of IP-related policy that you
    +  should understand before publishing on Google Play. In each area you'll find
    +  best practices and examples to help you avoid common types of mistakes and
    +  violations.
    +</p>
    +
    +<p>
    +  For more information about Google Play policies that apply to your apps and
    +  content, please see the <a href=
    +  "http://play.google.com/about/developer-content-policy.html" target=
    +  "_policies">Developer Program Policies</a> and <a href=
    +  "http://play.google.com/about/developer-distribution-agreement.html" target=
    +  "_policies">Developer Distribution Agreement</a>.
    +</p>
    +
    +
    +
    +<h2 id="copyright">Copyright Infringement</h2>
    +
    +<p>
    +  Copyright is the legal right granted to an author or creator for a literary,
    +  dramatic or artistic piece of work. As soon as you create an original piece
    +  of work and fix it in a tangible medium, the work is automatically protected
    +  by copyright law and you are the owner of the copyright. Likewise, when other
    +  people create content, they may own the copyrights for those works.
    +</p>
    +
    +
    +<div class="sidebox-wrapper">
    +<div class="sidebox">
    +<h2>How to report infringements</h2>
    +<p>If you feel your copyright is being infringed, you may file a Digital Millenium
    +   Copyright Act (DMCA) request. Please see <a 
    +   href="http://support.google.com/bin/request.py?&product=androidmarket&contact_type=lr_dmca"
    +   target="_policies">copyright procedures</a> for more information.</p>
    +</div>
    +</div>
    +
    +<p>
    +  Copyright infringement is an improper or unauthorized use of a copyrighted
    +  work. If you publish an app in Google Play that uses another party's copyrighted
    +  works improperly or without permission, your apps can be suspended and your
    +  developer account terminated.
    +</p>
    +
    +<p>
    +  As you design your app and prepare for publishing, make sure to review Google
    +  Play policies and analyze all of your content. If your app uses or links to
    +  another party's original work, make sure that your app is not infringing on
    +  copyright. Not all uses of another party’s work are infringements on
    +  copyright, and the rules vary by country and can be complex.
    +</p>
    +
    +<p>
    +  If you are unsure whether your use of another party's work infringes on a
    +  copyright, consider getting legal advice before publishing, or simply request
    +  permission to use the work from the copyright owner.
    +</p>
    +
    +<p>
    +  Here are some guidelines to help you avoid copyright infringement policy
    +  violations:
    +</p>
    +
    +<ul>
    +  <li>
    +    <strong>Respect copyright laws</strong>&mdash;Do not let your app infringe
    +    on the copyrights of others. That includes linking to other apps or web
    +    sites that contain obviously infringing material (please refer to the <a href="
    +    {@docRoot}distribute/googleplay/policies/spam.html#webview-spam">Spam in WebViews</a> guidelines), and using icons or images that are obvious infringements.
    +  </li>
    +
    +  <li>
    +    <strong>Know your app's content</strong>&mdash;Before you publish, look
    +    for content that may be protected by trademark or copyright in your app
    +    and get legal advice if necessary. Protected work could typically include
    +    product names, brands, images, music, and similar works.
    +  </li>
    +
    +  <li>
    +    <strong>Create original work</strong>&mdash;If you’re not sure whether
    +    something will violate another party's copyright, the safest approach is to
    +    create something that's completely original, such as images or audio
    +    that you’ve created yourself. When you create your own original content,
    +    you rarely have to worry about infringing on existing copyright.
    +  </li>
    +
    +  <li>
    +    <strong>Ask permission to use copyrighted work</strong>&mdash;If you want
    +    to use another party's copyrighted work in your app, you should ask for
    +    permission from the work's creator or copyright owner and include
    +    appropriate copyright attribution.
    +  </li>
    +</ul>
    +
    +<p>
    +  A common misunderstanding is believing that your app may use copyrighted
    +  content without permission, provided that you clearly indicate that your app
    +  is not the "official" app that readers may be familiar with. That is not the
    +  case. Even if you let users know that your app is "unofficial", it still
    +  violates Google Play policies if it uses or links to copyrighted content
    +  without permission. Also, this type of "unofficial" app may violate <a
    +  href="#impersonation">impersonation policies</a>.
    +</p>
    +
    +<p>
    +  The example app below shows an app that uses screenshots/images of known
    +  artists without their authorization and lists popular songs. The combination
    +  of these may induce users to download music ringtones that infringe on
    +  copyright. This is a violation of Google Play policy.
    +</p>
    +
    +<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
    +  <div class="heading">Images and downloads that violate copyright</div>
    +  <img src="{@docRoot}images/gp-policy-ip-copyright-violation.png">
    +</div>
    +
    +
    +<h2 id="impersonation">Impersonation</h2>
    +
    +<p>
    +  Impersonation is when an app attempts to imply a relationship to another app
    +  or developer, where no relationship actually exists.
    +</p>
    +
    +<p>
    +  For example, if your app displays the brand, icon, or title from another app
    +  in order to get to users to download your app, you are leading users to
    +  believe that your app is developed by the same entity as the other app and
    +  offers similar content or experience. This is an impersonation of the other
    +  app and developer, and it is a violation of Google Play policy. If you
    +  publish apps that violate impersonation policies, your apps can be suspended
    +  and your developer account terminated.
    +</p>
    +
    +<p>
    +  No matter what type of app you offer or what your motivation, don’t try to
    +  imply an endorsement or relationship to another company or product where none
    +  exists. Don’t try to establish your app as the "official" version of another
    +  party's work by prominently featuring their brand names or trademarks in your
    +  app title or description.
    +</p>
    +
    +<p>
    +  Even if your app description states that your app is an "unofficial" version,
    +  the use of the other app's branding, trademarks, and other content still can
    +  violate policy by presenting content that isn’t yours.
    +</p>
    +
    +<p>
    +  Here are some guidelines:
    +</p>
    +
    +<ul>
    +  <li>
    +    <strong>Don't pretend to be someone else</strong>&mdash; Don't represent
    +    that your content is produced by another company or organization if that is
    +    not the case.
    +  </li>
    +
    +  <li>
    +    <strong>Don't support infringing sites or apps</strong>&mdash; Don't divert
    +    users or provide links to any other site that mimics Google Play or
    +    represents itself as another application or service.
    +  </li>
    +
    +  <li>
    +    <strong>Don't use another app's branding</strong>&mdash; Don’t try to pass
    +    off your app as the official version of someone else’s property by using a
    +    person or entity (or brand) name in your app title or description.
    +  </li>
    +</ul>
    +
    +<p>
    +  Below is an example of an "unofficial" app that violates Google Play policy
    +  by impersonating another company and an existing product. Specifically:
    +</p>
    +
    +<ul>
    +  <li>The example app has a name and icon that appear to be impersonating an
    +  existing product.
    +  </li>
    +
    +  <li>The example developer name implies an endorsement or relationship to
    +  another company and their products where none exists.
    +  </li>
    +</ul>
    +
    +<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
    +  <div class="heading">App name, icon, and developer name that impersonate another</div>
    +  <img src="{@docRoot}images/gp-policy-ip-impersonation-violation.png">
    +</div>
    +
    +
    +<h2 id="trademarks">Trademark Infringement</h2>
    +
    +<p>
    +  A trademark is a brand that uniquely identifies a product and distinguishes
    +  it from other products. It can be a word, name, symbol, or combination of
    +  those that is intended to identify the source of the product. A trademark is
    +  specifically acquired by a company or other entity through a legal process
    +  and once acquired gives the owner exclusive rights to the trademark usage.
    +</p>
    +
    +<div class="sidebox-wrapper">
    +<div class="sidebox">
    +<h2>How to report infringements</h2>
    +<p>If you feel your trademark is being infringed, you can request a content review.
    +See <a href="http://support.google.com/bin/static.py?&ts=1114905&page=ts.cs"
    +target="_policies">Removing content from Google</a> for more information.</p>
    +</div>
    +</div>
    +
    +<p>
    +  Trademark infringement is improper or unauthorized use of a trademark. Google
    +  Play policies prohibit apps that infringe trademarks. If you publish apps in
    +  Google Play that use another party's trademarks, your apps can be suspended
    +  and your developer account terminated.
    +</p>
    +
    +<p>
    +  As you design your app and prepare for publishing, make sure to review Google
    +  Play policies and analyze all of your content. If your app uses a trademark
    +  not owned by you, or if you are not sure whether a brand is a trademark, you
    +  should get legal advice before publishing. As with copyright, the rules vary
    +  by country and can be complex.
    +</p>
    +
    +<p>
    +  Here are some guidelines for avoiding trademark infringement policy
    +  violations:
    +</p>
    +
    +<ul>
    +  <li>
    +    <strong>Understand and follow trademark laws</strong>&mdash;Don't let your
    +    app infringe on the trademarks of others.
    +  </li>
    +
    +  <li>
    +    <strong>Know your app's content</strong>&mdash;Before you publish, look for
    +    brands and potential trademarks used in your app and store listing and get
    +    legal advice if necessary.
    +  </li>
    +
    +  <li>
    +    <strong>Use a distinct name</strong>&mdash;Don't give your app a name that
    +    is confusingly similar to another company's trademark.
    +  </li>
    +
    +  <li>
    +    <strong>Don't use trademarks to imply a relationship</strong>&mdash;Don't
    +    describe your app using another company's trademarks in a way that implies
    +    an endorsement by or affiliation with the other company.
    +  </li>
    +
    +  <li>
    +    <strong>Use a distinct app icon and logo</strong>&mdash;Don't use a
    +    modified version of another company’s trademarked logo.
    +  </li>
    +</ul>
    +
    +<p>
    +  A common misunderstanding is believing that your app may use a brand or
    +  trademark without permission, provided you clearly indicate that the app is
    +  not the "official" or original app. That is not the case. Even if you let
    +  users know that your app is "unofficial", it still violates Google Play
    +  policies if it uses another party's trademarks. Also, this type of
    +  "unofficial" app may violate <a href="#impersonation">impersonation
    +  policies</a>.
    +</p>
    +
    +<p>
    +  Below is an example app that violates Google Play policies by infringing on
    +  another party's trademarks. Specifically:
    +</p>
    +
    +<ul>
    +  <li>The example app name is confusingly similar to another party's trademark.</li>
    +  <li>The example app icon is a modified version of a another party's logo.</li>
    +</ul>
    +
    +<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
    +  <div class="heading">App name and icon that infringe trademarks</div>
    +  <img src="{@docRoot}images/gp-policy-ip-trademark-violation.png">
    +</div>
    +
    +
    +<h2 id="other">DDA 4.4 Prohibited Actions</h2>
    +
    +<p>
    +  When you publish an app on Google Play, you agree to the terms of the
    +  Developer Distribution Agreement (DDA). Section 4.4 of the DDA prohibits certain
    +  types of actions on your part. For reference, you agree that you will not
    +  engage in any activity with the Market, including the development or
    +  distribution of Products, that interferes with, disrupts, damages, or
    +  accesses in an unauthorized manner the devices, servers, networks, or other
    +  properties or services of any third party including, but not limited to,
    +  Android users, Google or any mobile network operator.
    +</p>
    +
    +<p>
    +  For details, please refer to the complete <a href=
    +  "http://play.google.com/about/developer-distribution-agreement.html" target=
    +  "_policies">Developer Distribution Agreement</a>.
    +</p>
    \ No newline at end of file
    
    diff --git a/docs/html/distribute/googleplay/policies/spam.jd b/docs/html/distribute/googleplay/policies/spam.jd
    new file mode 100644
    index 0000000..602c89a
    --- /dev/null
    +++ b/docs/html/distribute/googleplay/policies/spam.jd
    
    @@ -0,0 +1,421 @@
    +page.title=Spam
    +@jd:body
    +
    +<div id="qv-wrapper">
    +<div id="qv">
    +  <h2>In This Document</h2>
    +  <ol>
    +    <li><a href="#keyword-spam">Spam in App Title and Description</a></li>
    +    <li><a href="#ratings">Spam in Ratings and Reviews</a></li>
    +    <li><a href="#webview-spam">Spam in WebViews</a></li>
    +    <li><a href="#wizard-spam">Spam from Wizards</a></li> 
    +    <li><a href="#message-spam">Spam in Messaging</a></li>
    +  </ol>
    +
    +  <h2>More Resources</h2>
    +  <ol>
    +    <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
    +    <li><a href="http://play.google.com/about/developer-distribution-agreement.html" target="_policies">Developer Distribution Agreement</a></li>
    +  </ol>
    +</div>
    +</div>
    +
    +<p>
    +  Google Play policies prohibit spam, to help ensure the best experience for
    +  Android users. Please do not publish deceptive, repetitive, or irrelevant
    +  content on Google Play. Not only will it lower your app's rating and cause
    +  negative reviews, it can result in your app being suspended or your developer
    +  account terminated.
    +</p>
    +
    +<p>
    +  As an app developer, it is your responsibility to ensure that your apps are
    +  free from spam and conform to the Google Play policies highlighted in this
    +  document. Before you publish, make sure that you understand what is
    +  considered spam on Google Play and check your apps for violations, even those
    +  that might be inadvertent. The sections below highlight best practices and
    +  common spam examples to help you avoid the most common types of policy
    +  violations.
    +</p>
    +
    +<p>
    +  For more information about Google Play policies that apply to your apps and
    +  content, please see the <a href=
    +  "http://play.google.com/about/developer-content-policy.html" target=
    +  "_policies">Developer Program Policies</a> and <a href=
    +  "http://play.google.com/about/developer-distribution-agreement.html" target=
    +  "_policies">Developer Distribution Agreement</a>.
    +</p>
    +
    +
    +<h2 id="keyword-spam">Spam in App Title and Description</h2>
    +
    +<p>
    +  When you publish an app on Google Play, you should pay special attention to
    +  the app's title and description in its store listing. Those fields are
    +  important because they make your app recognizable to users, and they help to
    +  drive downloads by highlighting what's great about your app. A memorable
    +  title and compelling description are essential to effective marketing, but
    +  you should realize that these must follow Google Play policies, just as your
    +  app content must do.
    +</p>
    +
    +<p>
    +  Many developers unknowingly violate spam policy in their app titles and
    +  descriptions in ways that are easy to avoid. In general, you can
    +  avoid spam violations in your app title and description by following these
    +  best practices:
    +</p>
    +
    +<ul>
    +  <li>
    +    <strong>Highlight what's great about your app</strong>&mdash;Share
    +    interesting and exciting facts about your app with users. Help users
    +    understand what makes your app special.
    +  </li>
    +
    +  <li>
    +    <strong>Describe your app accurately</strong>&mdash;Make sure the title
    +    and description describe the app function and user experience accurately.
    +  </li>
    +
    +  <li>
    +    <strong>Don't use repetitive keywords</strong>&mdash;Avoid keywords that
    +    are repetitive or excessive.
    +  </li>
    +
    +  <li>
    +    <strong>Don't include unrelated keywords or references</strong> &mdash;
    +    Your description should not be loaded with irrelevant keywords in an
    +    attempt to manipulate ranking or relevancy.
    +  </li>
    +
    +  <li>
    +    <strong>Keep it brief</strong>&mdash;Keep the description succinct and
    +    straightforward. Shorter descriptions tend to give a better user experience
    +    on devices with smaller displays. Excessive length, detail, or repetition
    +    can violate spam policy.
    +  </li>
    +</ul>
    +
    +<p>
    +  Here's an example app title and description that follows best practices and
    +  does not violate Google Play spam policies.
    +</p>
    +
    +<div class="example-block good" style="width:100%;float:none;margin:.5em auto 2em 0;">
    +  <div class="heading">Best practice: App description</div>
    +  <table>
    +  <tr>
    +    <td>App Title:</td>
    +    <td>Kids puzzle: Identify Turtles</td>
    +  </tr>
    +  <tr>
    +    <td style="white-space:nowrap;">App Description:</td>
    +    <td>
    +      <p>This is the perfect app to have a good time with your children. It
    +        is designed to help kids learn different species of turtles through
    +        cute pictures and amusing puzzle games.</p>
    +      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have
    +        your child drag images around the screen to fit them into the shaded
    +        region. Phonics is also utilized, as a child can also tap the word
    +        below the image and hear the name pronounced.</p>
    +    </td>
    +  </tr>
    +  </table>
    +</div>
    +
    +<p>
    +  The sections below highlight common types of policy violations in an app
    +  title and description, illustrated with variations on the best practice
    +  example. 
    +</p>
    +
    +<h3 id="repetitive-keywords">Repetitive keywords</h3>
    +
    +<p>
    +  Your app description should not include keywords that are repetitive or excessive.
    +</p>
    +
    +<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
    +  <div class="heading">Description includes repetitive keywords</div>
    +  <table>
    +  <tr>
    +    <td>App Title:</td>
    +    <td>Kids puzzle: Identify Turtles</td>
    +  </tr>
    +  <tr>
    +    <td style="white-space:nowrap;">App Description:</td>
    +    <td>
    +      <p>This is the perfect app to have a good time with your children. It is
    +        designed to help kids learn different species of turtles through cute
    +        pictures and amusing puzzle games.</p>
    +      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your
    +        child drag images around the screen to fit them into the shaded region.
    +        Phonics is also utilized, as a child can also tap the word below the image
    +        and hear the name pronounced.</p>
    +      <p style="border:2px solid red;">KEYWORDS: game, games, fun, funny, child,
    +        children, kid, kids, puzzle, puzzle games, sound, turtle, turtles, sea turtles,
    +        turtles, turtle, turtles, tortoise, tortoises, tortoise, tortoise,  turtles,
    +        turtles, turtles, turtles, tortoises, tortoise</p>
    +    </td>
    +  </tr>
    +  </table>
    +</div>
    +
    +<h3 id="unrelated-keywords">Unrelated keywords or references</h3>
    +
    +<p>
    +  The description should not be loaded with irrelevant keywords in an attempt
    +  to manipulate ranking or relevancy in Google Play search results.
    +</p>
    +
    +<p>
    +  For example, if your app has nothing to do with Lady Gaga, then she shouldn’t
    +  be included in your description. Also, do not add highly searched, irrelevant
    +  keywords that are unrelated to the function of the app. This is in breach of
    +  policy.
    +</p>
    +
    +<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
    +  <div class="heading">Description includes unrelated keywords or references</div>
    +  <table>
    +  <tr>
    +    <td>App Title:</td>
    +    <td>Kids puzzle: Identify Turtles</td>
    +  </tr>
    +  <tr>
    +    <td style="white-space:nowrap;">App Description:</td>
    +    <td>
    +      <p>This is the perfect app to have a good time with your children. It is designed to
    +        help kids learn different species of turtles through cute pictures and amusing puzzle
    +        games.</p>
    +      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child drag
    +        images around the screen to fit them into the shaded region. Phonics is also utilized,
    +        as a child can also tap the word below the image and hear the name pronounced.</p>
    +      <p style="border:2px solid red;">This game is as addictive as Angry Birds, more social
    +        than Facebook and Twitter, and has a soundtrack reminiscent of Katy Perry and Lady
    +        Gaga.</p>
    +      <p style="border:2px solid red;">KEYWORDS: Angry Birds, Facebook, Twitter, Katy Perry,
    +        Lady Gaga</p>
    +    </td>
    +  </tr>
    +  </table>
    +</div>
    +
    +<h3 id="excessive-detail">Excessive detail, references to your other apps</h3>
    +
    +<p>
    +  Your app description should avoid excessive detail and references to your
    +  other apps or products. For example, you should not list all of the details
    +  of content included in the app or its various components, as shown in the
    +  example below. Also, the description should not include any references to
    +  other apps you’ve published.
    +</p>
    +
    +<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
    +  <div class="heading">Description includes excessive detail, references to your other apps</div>
    +  <table>
    +  <tr>
    +    <td>App Title:</td>
    +    <td>Kids puzzle: Identify Turtles</td>
    +  </tr>
    +  <tr>
    +    <td style="white-space:nowrap;">App Description:</td>
    +    <td>
    +      <p>This is the perfect app to have a good time with your children. It is designed
    +        to help kids learn different species of turtles through cute pictures and amusing
    +        puzzle games.</p>
    +      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child
    +        drag images around the screen to fit them into the shaded region. Phonics is also
    +        utilized, as a child can also tap the word below the image and hear the name
    +        pronounced.</p>
    +      <p style="border:2px solid red;">Turtles included in the app: Alligator
    +        Snapping Turtle, Asian Box Turtle, Bog Turtle, Common Musk Turtle, Common Snapping
    +        Turtle, Diamondback Terrapin, Eastern Box Turtle, Eastern Mud Turtle, Eastern Painted
    +        Turtle, False Map Turtle, Florida Pond Cooter, Florida Softshell Turtle, Green Sea
    +        Turtle, Map Turtle, Matamata Ornate Box Turtle, Red-bellied Side-necked Turtle,
    +        Red-eared Slider, Smooth Softshell Turtle, Spiny Softshell Turtle, Spotted Turtle,
    +        Western Painted Turtle, Wood Turtle, Yellow-bellied Slider</p>
    +      <p style="border:2px solid red;">If you like this app try our other free apps:<br />
    +       ★ Fun Zoo<br />
    +       ★ CD Guns<br />
    +       ★ Dessert House<br />
    +       ★ Playground<br />
    +       ★ 578 Weapons</p>
    +    </td>
    +  </tr>
    +  </table>
    +</div>
    +
    +
    +<h2 id="ratings">Spam in Ratings and Reviews</h2>
    +
    +<p>
    +  Ratings and reviews are benchmarks of app quality and users depend on them to
    +  be authentic and relevant. As an app developer, you should not attempt to
    +  artificially influence your app's ratings and reviews or those of your
    +  competitor, such as by posting fake ratings or reviews or including spam
    +  content in app reviews. The sections below provide guidelines for rating and
    +  reviewing apps.
    +</p>
    +
    +<p>
    +  So that you can stay in touch with any issues that users are having with your
    +  app, you should read through your ratings and reviews on a regular basis. If
    +  you choose to reply to reviews, make sure to keep your reply focused on the
    +  actual issues raised in the user's comments and do not ask for a higher
    +  rating.
    +</p>
    +
    +<p>
    +  If you see an app or developer reply that doesn’t follow these guidelines,
    +  you can report it. See <a href=
    +  "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113417&topic=2364761&ctx=topic"
    +  target="_policies">Inappropriate content in comments and applications</a> for
    +  more information.
    +</p>
    +
    +<div class="example-block bad" style="width:440px;">
    +  <div class="heading">Inappropriate content in a review</div>
    +  <img src="{@docRoot}images/gp-policy-spam-negreview.png">
    +</div>
    +
    +<div class="example-block bad" style="margin-top:3em;">
    +  <div class="heading">Soliciting ratings</div>
    +  <img src="{@docRoot}images/gp-policy-spam-reqrating.png">
    +</div>
    +
    +<h3 id="fake-ratings">Fake or inappropriate ratings and reviews</h3>
    +
    +<p>
    +  To help ensure the quality of ratings and reviews, Google Play policies limit
    +  the ways that individuals can use ratings and reviews. In particular, note
    +  that it is a violation of policy to use ratings and reviews to influence the
    +  placement of any app in Google Play.
    +</p>
    +
    +<p>
    +  As an app developer, make sure that you follow these guidelines:
    +</p>
    +
    +<ul>
    +  <li>
    +    <strong>Don't try to manipulate ratings</strong>&mdash;Do not engage in
    +    attempts to manipulate the ratings, reviews, or ranking of your apps,
    +    either directly or indirectly, or by manipulating the ratings of your
    +    competitors. Do not attempt to artificially boost reviews, ratings, or
    +    installs through any means.
    +  </li>
    +
    +  <li>
    +    <strong>Don't solicit ratings through incentives</strong>&mdash;Do not
    +    offer users any incentives to rate your app, such as offering rewards of
    +    any kind or tying app functionality to rating.
    +  </li>
    +
    +  <li>
    +    <strong>Don't rate apps multiple times</strong>&mdash;Do not review or
    +    rate any app multiple times in an attempt to influence its placement in
    +    Google Play.
    +  </li>
    +
    +  <li>
    +    <strong>Don't add improper content to reviews</strong>&mdash;Do not
    +    include affiliate, coupon, game codes, email addresses, or links to
    +    websites or other apps in your reviews. If you are responding to a user
    +    review, feel free to include references to helpful resources such as a
    +    support address or FAQ page.
    +  </li>
    +</ul>
    +
    +<h3 id="solicited-ratings">Soliciting ratings from users</h3>
    +
    +<p>
    +  In general, <strong>do not offer incentives for ratings</strong>. You should
    +  not offer users incentives of any kind for rating your app (or any other app)
    +  on Google Play, and you should not tie your app's functionality or content to
    +  rating in any way.
    +</p>
    +
    +<p>
    +  It's acceptable to ask users to rate your app without incentives, for
    +  example: "If you like this game, rate us in Google Play!" On the other hand,
    +  it's a policy violation to ask users to rate your app based on incentives,
    +  for example: "Rate this app and get 500 coins" or "Rate this app 5 stars and
    +  get you 500 coins!"
    +</p>
    +
    +
    +<h2 id="webview-spam" style="clear:right">Spam in WebViews</h2>
    +
    +<p>
    +  Apps published on Google Play should provide their own content. Do not
    +  publish an app whose primary function is to reproduce or frame someone else’s
    +  website (unless you have permission).
    +</p>
    +
    +<p>
    +  Similarly, do not publish an app whose primary function is to drive affiliate
    +  traffic to a website. Although affiliate deals can exist where an app's
    +  primary purpose is delivering its own content or functionality, it's a
    +  violation of Google Play policies to publish an app whose primary (or
    +  only) purpose is to direct affiliate traffic to another website.
    +</p>
    +
    +<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
    +  <div class="heading">WebView spam</div>
    +  <table>
    +  <tr>
    +    <td>App Title:</td>
    +    <td>Kids puzzle: Desktop Browser for Turtoogle Game</td>
    +  </tr>
    +  <tr>
    +    <td>Developer:</td>
    +    <td>AAZZZ <span style="border:2px solid red;">(not affiliated with Turtoogle
    +      Inc.)</span></td>
    +  </tr>
    +  <tr>
    +    <td style="white-space:nowrap;">App Description:</td>
    +    <td>
    +      <p>Have you ever wanted to use the full, desktop web version of Turtoogle
    +        Game from your phone or tablet instead of the Turtoogle Game mobile app
    +        or Turtoogle Game mobile web site?</p>
    +      <p style="border:2px solid red;">This app lets you access Turtoogle Game
    +        on your Android device in the same way as you access the game on your
    +        desktop computer, and with all the same Turtoogle Game features.</p>
    +    </td>
    +  </tr>
    +  </table>
    +</div>
    +
    +
    +<h2 id="wizard-spam">Spam from Wizards</h2>
    +
    +<p>
    +  Apps that are created by an automated tool or wizard service must not be
    +  submitted to Google Play by the operator of that service on behalf of other
    +  persons. Such tools often produce too many duplicative or low-quality
    +  apps which crowd the higher-quality apps in the Play Store.
    +</p>
    +
    +<p>
    +  Please be advised that apps created by an automated tool are only permissible
    +  if the app end-product complies with Google Play policies and is published in
    +  the Play Store through a developer account that is registered and owned by
    +  you.
    +</p>
    +
    +
    +<h2 id="message-spam">Spam in Messaging</h2>
    +
    +<p>
    +  Your app may not send SMS, email, or other messages on behalf of the user
    +  without providing the user with the ability to confirm the content and intended
    +  recipient.
    +</p>
    +
    +<p>
    +  Google Play will aggressively remove applications that are found to send or
    +  modify SMS messages without user knowledge or consent.
    +</p>
    \ No newline at end of file
    
    diff --git a/docs/html/distribute/googleplay/publish/register.jd b/docs/html/distribute/googleplay/publish/register.jd
    index dd73898..5f1f2ea 100644
    --- a/docs/html/distribute/googleplay/publish/register.jd
    +++ b/docs/html/distribute/googleplay/publish/register.jd
    
    @@ -23,7 +23,7 @@
     
     <ul>
     <li>Register for a Google Play publisher account</li>
    -<li>If you will sell apps, set up a Google Checkout Merchant Account</li>
    +<li>If you will sell apps, set up a Google Wallet Merchant Account</li>
     <li>Explore the Google Play Developer Console and learn about the tools for publishing</li>
     </ul>
     
    @@ -57,11 +57,11 @@
     a Google Checkout account, you can quickly set one up during the process.</li>
     </ol>
     
    -<p>When your registration is verified, you’ll be notified at the email address you specified during registration. </p>
    +<p>When your registration is verified, you’ll be notified at the email address you specified during registration.</p>
     
    -<h3>Set up a Google Checkout Merchant account</h3>
    +<h3>Set up a Google Wallet Merchant account</h3>
      
    -<p>If you want to sell products on Google Play &mdash; priced apps, in-app products, or subscriptions &mdash; you will also need to set up a Google Checkout <a href="http://checkout.google.com/sell">Merchant Account</a>. You can do that at any time, but make sure to first review the list of <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a>.</p>
    +<p>If you want to sell products on Google Play &mdash; priced apps, in-app products, or subscriptions &mdash; you will also need to set up a Google Wallet Merchant Account. You can do that at any time, but make sure to first review the list of <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a>.</p>
     
     <p>To set up a Merchant account from the Developer Console:</p>
     
    
    diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
    index 24a30f1..6d7e3e2 100644
    --- a/docs/html/distribute/googleplay/quality/tablet.jd
    +++ b/docs/html/distribute/googleplay/quality/tablet.jd
    
    @@ -5,7 +5,7 @@
     <h2>Checklist</h2>
     <ol>
     
    -<li><a href="#core-app-quality">1. Test for Core App Quality</a></li>
    +<li><a href="#core-app-quality">1. Test for Core Tablet App Quality</a></li>
     <li><a href="#optimize-layouts">2. Optimize your layouts</a></li>
     <li><a href="#use-extra-space">3. Use the extra screen area</a></li>
     <li><a href="#use-tablet-icons">4. Use assets designed for tablets</a></li>
    @@ -14,16 +14,17 @@
     <li><a href="#offer-full-feature-set">7. Offer the app's full feature set</a></li>
     <li><a href="#hardware-requirements">8. Don’t require hardware features</a></li>
     <li><a href="#support-screens">9. Declare tablet screen support</a></li>
    -<li><a href="#google-play">10. Follow best practices for publishing in Google Play</a></li>
    +<li><a href="#google-play">10. Showcase your tablet UI</a></li>
    +<li><a href="#google-play-bp">11. Follow publishing best practices</a></li>
     
     </ol>
     <h2>Testing</h2>
     <ol>
    +<li><a href="#basic-technical-checks">Basic Technical Checks for Tablets</a></li>
     <li><a href="#test-environment">Setting Up a Test Environment</a></li>
     </ol>
     </div></div>
     
    -
     <p>Before you publish an app on Google Play, it's important to make sure that
     the app meets the basic expectations of tablet users through compelling features
     and an intuitive, well-designed UI. </p>
    @@ -46,32 +47,81 @@
     that can help you address the topics raised in each task.</p>
     
     
    -<h2 id="core-app-quality">1. Test for Core App Quality</h2>
    +<h2 id="core-app-quality">1. Test for Core Tablet App Quality</h2>
    +
    +<p>Before publishing, make sure that your app and it's store listing meet the
    +  core quality guidlines below. </p>
    +
    +<h5>Core app quality</h5>
     
     <p>The first step in delivering a great tablet app experience is making sure
    -that it meets the <em>core app
    -quality criteria</em> for all of the devices and form factors that the app is
    -targeting. For complete information, see the <a
    -href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Checklist</a>. 
    +that it meets the <em>core app quality criteria</em> for all of the devices
    +and form factors that the app is targeting. For complete information, see the <a
    +href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>. 
     </p>
     
    -<p>To assess the quality of your app on tablets &mdash; both for core app quality
    -and tablet app quality &mdash; you need to set up a suitable
    -hardware or emulator environment for testing. For more information, 
    -see <a href="#test-environment">Setting Up a Test Environment</a>.</p>
    +<h5>Basic technical checks for tablets</h5>
    +<p>
    +  Before publishing, you should also ensure that your app passes several basic
    +  technical checks, such as:
    +</p>
     
    -<table>
    -<tr>
    -<td><p>Related resources:</p>
    -<ul style="margin-top:-.5em;">
    -<li><strong><a
    -href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality
    -Guidelines</a></strong> &mdash; A set of core quality criteria that all Android
    -apps should meet on all targeted devices.</li>
    +<ul>
    +  <li>Targeting appropriate Android versions</li>
    +  <li>Specifying any feature dependencies properly</li>
    +  <li>Declaring support for appropriate screens</li>
     </ul>
    -</td>
    -</tr>
    -</table>
    +
    +<p>
    +  For details, see <a href="#basic-technical-checks">Basic Technical
    +  Checks</a>.
    +</p>
    +
    +<h5>Tablet screenshots and other promotional tools</h5>
    +
    +<p>Make sure that you upload screenshots of your tablet UI to the
    +  Developer Console and highlight your tablet experience in your app description,
    +  video, and promotional campaigns. For details, see <a href="#google-play">Showcase your
    +  tablet UI in Google Play.</a></p>
    +
    +<h5>Test environment</h5>
    +
    +<p>
    +  To assess the quality of your app on tablets, you need to set up a suitable
    +  hardware or emulator environment for testing. For more information, see
    +  <a href="#test-environment">Setting Up a Test Environment</a>.
    +</p>
    +<p>
    +  Note that a successful tablet app will go <em>well beyond the core and tablet
    +  app quality criteria</em> to offer a custom tablet experience to users. Read
    +  the sections below for ideas on how to plan and develop a great tablet UI for
    +  your app.
    +</p>
    +
    +
    +<div class="rel-resources">
    +  <h3>
    +    Related resources
    +  </h3>
    +
    +  <ul>
    +    <li>
    +      <a href="{@docRoot}distribute/googleplay/quality/core.html">Core App
    +      Quality</a>&mdash;A set of core quality criteria that all Android apps
    +      should meet on all targeted devices.
    +    </li>
    +
    +    <li>
    +      <a href="#basic-technical-checks">Basic Technical Checks for
    +      Tablets</a>&mdash;Additional quality criteria for any app that is
    +      targeting, designed for, or distributable to Android tablets.
    +    </li>
    +    <li>
    +      <a href="#google-play">Showcase your tablet UI on Google Play</a>&mdash;Information
    +      on how to upload tablet screenshots and promote your tablet app.
    +    </li>
    +  </ul>
    +</div>
     
     <h2 id="optimize-layouts">2. Optimize your layouts for larger screens</h2>
     
    @@ -97,9 +147,12 @@
     <p>Here are some suggestions:</p>
     
     <div style="width:390px;float:right;margin:1.5em;margin-top:0em;">
    -<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png" style="width:390px;padding:4px;margin-bottom:0em;">
    +<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png"
    +style="width:390px;padding:4px;margin-bottom:0em;">
     <p class="image-caption" style="padding:0em .5em .5em 2em"><span
    -style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane layouts lead to awkward whitespace and excessive line lengths. Use padding to reduce the width of UI elements and consider using multi-pane layouts.</p>
    +style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane
    +layouts lead to awkward whitespace and excessive line lengths. Use padding to
    +reduce the width of UI elements and consider using multi-pane layouts.</p>
     </div>
     
     <ul>
    @@ -131,29 +184,51 @@
     multi-pane UI for tablets (see next section).</li>
     </ul>
     
    -<table>
    -<tr>
    -<td><p>Related resources:</p>
    -<ul style="margin-top:-.5em;">
    -<li><strong><a href="http://developer.android.com/design/style/metrics-grids.html">Metrics and Grids
    -</a></strong> &mdash; Android Design document that explains ....</li>
    -<li><strong><a href="http://developer.android.com/design/style/devices-displays.html">Devices and Displays
    -</a></strong> &mdash; Android Design document that explains ....</li>
    -<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> &mdash; Developer documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
    -<li><strong><a href="http://developer.android.com/guide/practices/screens_support.html#ConfigurationExamples">Configuration examples
    -</a></strong> &mdash; Examples of how to declare layouts and other resources for specific screen sizes.</a></li>
    -</ul>
    -</td>
    -</tr>
    -</table>
    +<div class="rel-resources">
    +  <h3>
    +    Related resources
    +  </h3>
    +
    +  <ul>
    +    <li>
    +      <a href=
    +      "{@docRoot}design/style/metrics-grids.html">Metrics
    +      and Grids</a>&mdash;Android Design document that explains how to create
    +      layouts based on density-independent grids.
    +    </li>
    +
    +    <li>
    +      <a href=
    +      "{@docRoot}design/style/devices-displays.html">Devices
    +      and Displays</a>&mdash;Android Design document that explains how to
    +      design a UI that works well on different devices and
    +      screen sizes.
    +    </li>
    +
    +    <li>
    +      <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
    +      Screens</a>&mdash;Developer documentation that explains the details of
    +      managing UI for best display on multiple screen sizes.
    +    </li>
    +
    +    <li>
    +      <a href=
    +      "{@docRoot}guide/practices/screens_support.html#ConfigurationExamples">
    +      Configuration examples</a>&mdash;Examples of how to declare layouts and
    +      other resources for specific screen sizes.
    +    </li>
    +  </ul>
    +</div>
     
     
     <h2 id="use-extra-space">3. Take advantage of extra screen area available on tablets</h2>
     
     <div style="width:290px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
    -<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png" style="width:280px;padding:4px;margin-bottom:0em;">
    +<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png"
    +style="width:280px;padding:4px;margin-bottom:0em;">
     <p class="image-caption" style="padding:0em .5em .5em 1.5em"><span
    -style="font-weight:500;">Multi-pane layouts</span> result in a better visual balance on tablet screens, while offering more utility and legibility.</p>
    +style="font-weight:500;">Multi-pane layouts</span> result in a better visual
    +balance on tablet screens, while offering more utility and legibility.</p>
     </div>
     
     <p>Tablet screens provide significantly more screen real estate to your app,
    @@ -175,39 +250,58 @@
     <li>Plan how you want the panels of your compound views to reorganize when
     screen orientation changes.</li>
     
    -
    -
     <div style="width:490px;margin:1.5em auto 1.5em 0;">
    -
     <div style="">
    -<img src="{@docRoot}images/ui-ex-single-panes.png" style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
    +<img src="{@docRoot}images/ui-ex-single-panes.png"
    +style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
     <img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
     <p class="image-caption" style="padding:.5em"><span
    -style="font-weight:500;">Compound views</span> combine several single views from a handset UI <em>(above)</em> into a richer, more efficient UI for tablets <em>(below)</em>. </p>
    +style="font-weight:500;">Compound views</span> combine several single views from a
    +handset UI <em>(above)</em> into a richer, more efficient UI for tablets
    +<em>(below)</em>. </p>
     </div>
     </div>
     
     <li>While a single screen is implemented as an {@link android.app.Activity}
     subclass, consider implementing individual content panels as {@link
    -android.app.Fragment} subclasses. This lets you maximize code reuse across
    -different form factors and across screens that share content.</li>
    +android.app.Fragment} subclasses. This lets you
    +maximize code reuse across different form factors and across screens that
    +share content.</li>
     <li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
     different layouts in the appropriate screen size buckets (such as
     <code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
     <code>sw600dp</code>/<code>sw720</code>).</li>
     </ul>
     
    -<table>
    -<tr>
    -<td><p>Related resources:</p>
    -<ul style="margin-top:-.5em;">
    -<li><strong><a href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane Layouts</a></strong> &mdash; Android Design guide for using multi-pane UI, including examples of how to flatten navigation and integrate more content into your tablet UI.</li>
    -<li><strong><a href="{@docRoot}training/design-navigation/multiple-sizes.html">Planning for Multiple Touchscreen Sizes</a></strong> &mdash; Android Training class that walks you through the essentials of planning an intuitive, effective navigation for tablets and other devices. </li>
    -<li><strong><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a></strong> &mdash; Android Training class that walks you through the essentials of planning an intuitive, effective navigation for tablets and other devices. </li>
    -</ul>
    -</td>
    -</tr>
    -</table>
    +<div class="rel-resources">
    +  <h3>
    +    Related resources
    +  </h3>
    +
    +  <ul>
    +    <li>
    +      <a href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane
    +      Layouts</a>&mdash;Android Design guide for using multi-pane UI, including
    +      examples of how to flatten navigation and integrate more content into
    +      your tablet UI.
    +    </li>
    +
    +    <li>
    +      <a href=
    +      "/training/design-navigation/multiple-sizes.html">Planning for Multiple
    +      Touchscreen Sizes</a>&mdash;Android Training class that walks you through
    +      the essentials of planning an intuitive, effective navigation for tablets
    +      and other devices.
    +    </li>
    +
    +    <li>
    +      <a href="{@docRoot}training/multiscreen/index.html">Designing for
    +      Multiple Screens</a>&mdash;Android Training class that walks you through
    +      the essentials of planning an intuitive, effective navigation for tablets
    +      and other devices.
    +    </li>
    +  </ul>
    +</div>
     
     
     <h2 id="use-tablet-icons">4. Use Icons and other assets that are designed for tablet screens</h2>
    @@ -268,18 +362,41 @@
     gets loaded.</li>
     </ul>
     
    -<table>
    -<tr>
    -<td><p>Related resources:</p>
    -<ul style="margin-top:-.5em;">
    -<li><strong><a href="{@docRoot}design/style/iconography.html">Iconography</a></strong> &mdash; Android Design document that shows how to use various types of icons.</li>
    -<li><strong><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></strong> &mdash; Developer documentation on how to provide sets of layouts and drawable resources for specific ranges of device screens. </li>
    -<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> &mdash; API Guide documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
    -<li><strong><a href="{@docRoot}training/basics/supporting-devices/screens.html">Supporting Different Screens</a></strong> &mdash; Android Training class that takes you through the process of optimizing the user experience for different screen sizes and densities.</li>
    -</ul>
    -</td>
    -</tr>
    -</table>
    +<div class="rel-resources">
    +  <h3>
    +    Related resources
    +  </h3>
    +
    +  <ul>
    +    <li>
    +      <a href="{@docRoot}design/style/iconography.html">Iconography</a>&mdash; Android
    +      Design document that shows how to use various types of icons.
    +    </li>
    +
    +    <li>
    +      <a href=
    +      "/guide/topics/resources/providing-resources.html">Providing
    +      Resources</a>&mdash;Developer documentation on how to provide
    +      sets of layouts and drawable resources for specific ranges of device
    +      screens.
    +    </li>
    +
    +    <li>
    +      <a href="{@docRoot}guide/practices/screens_support.html">Supporting
    +      Multiple Screens</a>&mdash;API Guide documentation that
    +      explains the details of managing UI for best display on multiple screen
    +      sizes.
    +    </li>
    +
    +    <li>
    +      <a href=
    +      "/training/basics/supporting-devices/screens.html">Supporting Different
    +      Screens</a>&mdash;Android Training class that takes you
    +      through the process of optimizing the user experience for different
    +      screen sizes and densities.
    +    </li>
    +  </ul>
    +</div>
     
     
     <h2 id="adjust-font-sizes">5. Adjust font sizes and touch targets for tablet screens</h2>
    @@ -300,29 +417,49 @@
     titles, and other elements.</li>
     <li>The recommended touch-target size for onscreen elements is 48dp (32dp
     minimum) &mdash; some adjustments may be needed in your tablet UI. Read <a
    -href="http://developer.android.com/design/style/metrics-grids.html">Metrics and
    +href="{@docRoot}design/style/metrics-grids.html">Metrics and
     Grids
     </a> to learn about implementation strategies to help most of your users. To
     meet the accessibility needs of certain users, it may be appropriate to use
     larger touch targets. </li>
     <li>When possible, for smaller icons, expand the touchable area to more than
    -48dp using {@link android.view.TouchDelegate} or just centering the icon within
    -the transparent button.</li>
    +48dp using {@link android.view.TouchDelegate}
    +or just centering the icon within the transparent button.</li>
     </ul>
     
    -<table>
    -<tr>
    -<td><p>Related resources:</p>
    -<ul style="margin-top:-.5em;">
    -<li><strong><a href="http://developer.android.com/design/style/metrics-grids.html">Metrics and Grids
    -</a></strong> &mdash; Android Design document that explains how to arrange and size touch targets and other UI elements on the screen.</li>
    -<li><strong><a href="{@docRoot}design/style/typography.html">Typography</a></strong> &mdash; Android Design document that gives an overview of how to use typography in your apps. </li>
    -<li><strong><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></strong> &mdash; Developer documentation that explains the details of managing UI for best display on multiple screen sizes.</li>
    -<li><strong><a href="{@docRoot}training/multiscreen/screendensities.html">Supporting Different Densities</a></strong> &mdash; Android Training class that shows you how to provide sets of layouts and drawable resources for specific ranges of device screens. </li>
    -</ul>
    -</td>
    -</tr>
    -</table>
    +<div class="rel-resources">
    +  <h3>
    +    Related resources
    +  </h3>
    +
    +  <ul>
    +    <li>
    +      <a href=
    +      "{@docRoot}design/style/metrics-grids.html">Metrics
    +      and Grids</a> &mdash;Android Design document that explains how to arrange
    +      and size touch targets and other UI elements on the screen.
    +    </li>
    +
    +    <li>
    +      <a href="{@docRoot}design/style/typography.html">Typography</a>&mdash;Android
    +      Design document that gives an overview of how to use typography in your
    +      apps.
    +    </li>
    +
    +    <li>
    +      <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
    +      Screens</a>&mdash;Developer documentation that explains the details of
    +      managing UI for best display on multiple screen sizes.
    +    </li>
    +
    +    <li>
    +      <a href="{@docRoot}training/multiscreen/screendensities.html">Supporting
    +      Different Densities</a>&mdash;Android Training class that shows you how
    +      to provide sets of layouts and drawable resources for specific ranges of
    +      device screens.
    +    </li>
    +  </ul>
    +</div>
     
     
     <h2 id="adjust-widgets">6. Adjust sizes of home screen widgets for tablet screens</h2>
    @@ -343,17 +480,25 @@
     possible.</li>
     </ul>
     
    -<table>
    -<tr>
    -<td><p>Related resources:</p>
    -<ul style="margin-top:-.5em;">
    -<li><strong><a href="{@docRoot}guide/topics/appwidgets/index.html#MetaData">Adding the AppWidgetProviderInfo Metadata
    -</a></strong> &mdash; API Guide that explains how to set the height and width dimensions of a widget.</li>
    -<li><strong><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design Guidelines</a></strong> &mdash; API Guide that provides best practices and techniques for designing and managing the size of widgets.  </li>
    -</ul>
    -</td>
    -</tr>
    -</table>
    +<div class="rel-resources">
    +  <h3>
    +    Related resources
    +  </h3>
    +
    +  <ul>
    +    <li>
    +      <a href="{@docRoot}guide/topics/appwidgets/index.html#MetaData">Adding the
    +      AppWidgetProviderInfo Metadata</a> &mdash;API Guide that explains how to
    +      set the height and width dimensions of a widget.
    +    </li>
    +
    +    <li>
    +      <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
    +      Design Guidelines</a>&mdash;API Guide that provides best practices and
    +      techniques for designing and managing the size of widgets.
    +    </li>
    +  </ul>
    +</div>
     
     
     <h2 id="offer-full-feature-set">7. Offer the app's full feature set to tablet users</h2>
    @@ -383,7 +528,8 @@
     </ul>
     
     
    -<h2 id="hardware-requirements">8. Don’t require hardware features that might not be available on tablets</h2>
    +<h2 id="hardware-requirements">8. Don’t require hardware features that might not be
    +  available on tablets</h2>
     
     <p>Handsets and tablets typically offer slightly different hardware support for
     sensors, camera, telephony, and other features. For example, many tablets are
    @@ -412,27 +558,46 @@
     href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">imply
     feature requirements</a> that might not be appropriate for tablets, except when
     accompanied by a corresponding <code>&lt;uses-feature&gt;</code> element
    -declared with the <code>android:required=”false”</code> attribute.</li>
    +declared with the <code>android:required=”false”</code> attribute.
    +<p>Here's an example of a dependency that's properly declared as "not required", so that 
    +it does not limit distribution to devices that do not support the dependency:</p>
    +<p><code>&lt;uses-feature android:name="android.hardware.telephony"
    +android:required="false" /&gt;</code></p></li>
     </ul>
     
     <p>In all cases, the app must function normally when the hardware features it
    -uses are not available and should offer “graceful degradation” and alternative
    +uses are not available and should offer "graceful degradation" and alternative
     functionality where appropriate. For example, if GPS is not supported on the device,
     your app could let the user set their location manually. The app should do
     run-time checking for the hardware capability that it needs and handle as needed.</p>
     
    -<table>
    -<tr>
    -<td><p>Related resources:</p>
    -<ul style="margin-top:-.5em;">
    -<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">Permissions that Imply Feature Requirements</a></strong> &mdash; A list of permissions that may cause unwanted filtering if declared in your app's manifest.</li>
    -<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a></strong> &mdash; Description and reference documentation for the <code>&lt;uses-feature&gt;</code> manifest element.</li>
    -<li><strong><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#testing">Testing the features required by your application</a></strong> &mdash; Description of how to determine the actual set of hardware and software requirements (explicit or implied) that your app requires.</li>
    -</ul>
    -</td>
    -</tr>
    -</table>
    +<div class="rel-resources">
    +<h3>
    +  Related resources
    +</h3>
     
    +<ul>
    +  <li>
    +    <a href=
    +    "/guide/topics/manifest/uses-feature-element.html#permissions">Permissions
    +    that Imply Feature Requirements</a>&mdash;A list of permissions that may
    +    cause unwanted filtering if declared in your app's manifest.
    +  </li>
    +  <li>
    +    <a href=
    +    "/guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>&mdash;Description
    +    and reference documentation for the <code>&lt;uses-feature&gt;</code>
    +    manifest element.
    +  </li>
    +
    +  <li>
    +    <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#testing">Testing
    +    the features required by your application</a>&mdash;Description of how to
    +    determine the actual set of hardware and software requirements (explicit or
    +    implied) that your app requires.
    +  </li>
    +</ul>
    +</div>
     
     <h2 id="support-screens">9. Declare support for tablet screen configurations</h2>
     
    @@ -442,77 +607,441 @@
     <ul>
     <li>Declare a <a
     href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a> element
    -with appropriate attributes, as needed.</li>
    +with appropriate attributes, as needed. For details, see <a 
    +href="#basic-technical-checks">Basic Technical Checks</a>
    +later in this document.</li>
     <li>If the app declares a <code>&lt;compatible-screens&gt;</code> element in the
     manifest, the element must include attributes that specify <em>all of the size and
     density combinations for tablet screens</em> that the app supports. Note that, if possible,
     you should avoid using this element in your app.</li>
     </ul>
     
    -<table>
    -<tr>
    -<td><p>Related resources:</p>
    -<ul style="margin-top:-.5em;">
    -<li><strong><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a></strong>
    -&mdash; Description and reference documentation for the <code>&lt;supports-screens&gt;</code>
    -manifest element.</li>
    -<li><strong><a href="{@docRoot}guide/practices/screens_support.html#DeclaringScreenSizeSupport">Declaring Screen Size
    -Support</a></strong> &mdash; Developer documentation that explains the details of managing UI
    -for best display on multiple screen sizes.</li>
    +<div class="rel-resources">
    +  <h3>
    +    Related resources
    +  </h3>
    +
    +  <ul>
    +    <li>
    +      <a href="#basic-technical-checks">Basic Technical
    +      Checks</a>&mdash;Includes details (see <a href="#TB-R4">TB-R4</a>) on how
    +      to properly declare screens support for tablet screen sizes.
    +    </li>
    +
    +    <li>
    +      <a href=
    +      "/guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>&mdash;Description
    +      and reference documentation for the <code>&lt;supports-screens&gt;</code>
    +      manifest element.
    +    </li>
    +
    +    <li>
    +      <a href=
    +      "/guide/practices/screens_support.html#DeclaringScreenSizeSupport">Declaring
    +      Screen Size Support</a>&mdash;Developer documentation that explains the
    +      details of managing UI for best display on multiple screen sizes.
    +    </li>
    +  </ul>
    +</div>
    +
    +
    +<h2 id="google-play">10. Showcase your tablet UI in Google Play</h2>
    +
    +<p>
    +  After you've done the work to create an rich, optimized UI for your tablet
    +  app, make sure that you let your customers know about it! Here are some key
    +  ways to promote your tablet app to users on Google Play.
    +</p>
    +
    +<h5>
    +  Upload screenshots of your tablet UI
    +</h5>
    +
    +<p>
    +  Tablet users want to know what your app is like on a tablet device, not on a
    +  phone. Capitalize on their interest by showing them screenshots of your
    +  tablet UI on your app's store listing page. You can upload tablet screenshots
    +  from the Developer Console. Here are some tips and guidelines:
    +</p>
    +
    +<ul style="margin-top:0;">
    +  <li>Your screenshots should show the core functionality of your app, not a
    +  startup or sign-in page. Wherever users will spend most of their time, that's
    +  what you should show in your screenshots.
    +  </li>
    +
    +  <li>Add screenshots taken on both 7-inch and 10-inch tablets, if possible.
    +  </li>
    +
    +  <li>It's recommended that you add screenshots taken in both landscape and
    +  portrait orientations, if possible.
    +  </li>
    +
    +  <li>Use screen captures if possible. Avoid showing actual device hardware in your
    +  screenshots.</li>
    +
    +  <li>The recommended resolution of your tablet screenshots is <strong>1280 x 720</strong>
    +  or higher in each orientation.
    +  </li>
    +
    +  <li>You can upload as many as 8 screenshots of your tablet UI for 7-inch tablets
    +  and an additional 8 for 10-inch tablets.
    +  </li>
     </ul>
    -</td>
    -</tr>
    -</table>
     
    -
    -<h2 id="google-play">10. Follow best practices for publishing in Google Play</h2>
    +<h5>
    +  Update your app description and release notes
    +</h5>
     
     <ul>
    -<li>Publish your app as a single APK for all screen sizes (handsets
    -and tablets), with a single Google Play listing:
    -  <ul style="margin-top:.25em;">
    -    <li>Easier for users to find your app from search, browsing, or promotions</li>
    -    <li>Easier for users to restore your app automatically if they get a new device.</li>
    -    <li>Your ratings and download stats are consolidated across all devices.</li>
    -    <li>Publishing a tablet app in a second listing can dilute ratings for your brand.</li>
    -  </ul>
    -</li>
    -<li>If necessary, you can alternatively choose to deliver your app using <a 
    -href="{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK Support</a>, 
    -although in most cases using a single APK to reach all devices is strongly recommended.</li>
    +  <li>In your app description, make sure to highlight that your app offers
    +  tablet-optimized UI and great features for tablet users. Consider adding some
    +  detail about how your tablet UI works and why users will like it.
    +  </li>
     
    -<li>Highlight your app’s tablet capabilities in the product details page:
    -  <ul style="margin-top:.25em;">
    -    <li>Add <strong>at least one screenshot taken while the app is running on a
    -    tablet</strong>. It's recommended that you add one screenshot of landscape orientation
    -    and one of portrait orientation, if possible. These screenshots make it clear to users
    -    that your app is designed for tablets and highlight all the effort you've put into designing
    -    a great tablet app experience.</li>
    -    <li>Mention tablet support in the app description.</li>
    -    <li>Include information about tablet support in the app's release notes and update
    -    information.</li>
    -    <li>In your app's promo video, add shots of your app running on a tablet.</li>
    -  </ul>
    -</li>
    -<li>Make sure you are distributing to tablet devices. Check the app's Supported Devices
    -list in the <a href="https://play.google.com/apps/publish/">Developer Console</a>
    -to make sure your app is not filtered from tablet devices that you want to target.</li>
    -
    -<li>Let tablet users know about your app! Plan a marketing or advertising campaign that
    -highlights the use of your app on tablets.</li>
    +  <li>Include information about tablet support in the app's release notes and
    +  update information.
    +  </li>
     </ul>
     
    +<h5>
    +  Update your promotional video
    +</h5>
    +
    +<p>
    +  Many users view an app's promotional video to get an idea of what the app is
    +  like and whether they'll enjoy it. For tablet users, capitalize on this
    +  interest by highlighting your app's tablet UI in your promotional video. Here
    +  are some tips and guidelines:
    +</p>
    +
    +<ul>
    +  <li>Add one or more shots of your app running on a tablet. To engage with
    +  tablet users most effectively, it's recommended that you promote your tablet
    +  UI in approximately equal proportion to your phone UI.
    +  </li>
    +
    +  <li>Show your tablet UI as early as possible in the video. Don't assume that
    +  tablet users will wait patiently through a feature walkthrough on a phone UI.
    +  Ideally, you should engage them immediately by showing the tablet UI within
    +  the first 10 seconds, or at the same point that you introduce the phone UI.
    +  </li>
    +
    +  <li>To make it clear that you are showing a tablet UI, include shots of your
    +  app running on a hand-held tablet device.
    +  </li>
    +
    +  <li>Highlight your app's tablet UI in the video's narrative or voiceover.
    +  </li>
    +</ul>
    +
    +<h5>
    +  Feature your tablet UI in your promotional campaigns
    +</h5>
    +
    +<p>
    +  Make sure to let tablet users know about your tablet UI in your promotional
    +  campaigns, web site, social posts, advertisements, and elsewhere. Here are
    +  some suggestions:
    +</p>
    +
    +<ul>
    +  <li>Plan a marketing or advertising campaign that highlights the use of your
    +  app on tablets.</li>
    +
    +  <li>Show your tablet app at its best in your promotional campaigns&mdash;use the <a href=
    +  "{@docRoot}distribute/promote/device-art.html">Device Art Generator</a> to
    +  quickly generate a high-quality promotional image of your app running on a
    +  7-inch or 10-inch tablet, in the orientation of your choice, with or without
    +  drop-shadow and screen glare. It's as simple as capture, drag, and drop.
    +  </li>
    +
    +  <li>Include a Google Play badge in your online promotions to let users link
    +  directly to your app's store listing. You can generate a badge in a variety
    +  of languages using the <a href=
    +  "{@docRoot}distribute/googleplay/promote/badges.html">Badge Generator</a>.
    +  </li>
    +</ul>
    +
    +<div class="rel-resources">
    +  <h3>
    +    Related resources
    +  </h3>
    +
    +  <ul>
    +    <li>
    +      <a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
    +      Checklist</a>
    +      &mdash;Recommendations on how to prepare your app for publishing, test
    +      it, and launch successfully on Google Play.
    +    </li>
    +
    +    <li>
    +      <a href="https://play.google.com/apps/publish/">Google Play
    +      Developer Console</a>&mdash;The tools console for publishing
    +      your app to Android users.
    +    </li>
    +    <li>
    +      <a href=
    +      "{@docRoot}distribute/googleplay/promote/badges.html">Google Play
    +      Badge Generator</a>&mdash;Create "Get it on Google Play" badges for your
    +      app in a variety of languages with a single click. 
    +    </li>
    +    <li>
    +      <a href=
    +      "{@docRoot}distribute/googleplay/promote/device-art.html">Device Art
    +      Generator</a>&mdash;Drag and drop tool that lets you instantly create production-
    +      ready art showing your app running on a tablet device. 
    +    </li>
    +  </ul>
    +</div>
    +
    +<h2 id="google-play-bp">11. Follow best practices for publishing in Google Play</h2>
    +
    +<p>Make sure that your app follows key best practices that ensure broad
    +  distribution to tablet devices. </p>
    +
    +<h5>Verify basic technical checks</h5>
    +
    +  <ul>
    +    <li>Verify that the app is targeting the proper Android versions and screen sizes 
    +    for Android tablets. Follow the <a href="#basic-technical-checks">Basic Technical
    +    Checks for Tablets</a> listed in the next section. </li>
    +    <li>After you've uploaded the app to the 
    +    <a href="https://play.google.com/apps/publish/">Developer Console</a>,
    +    check the APK's Supported Devices list to make sure that the app is not filtered
    +    from tablet devices that you want to target.</p></li>
    +  </ul>
    +
    +<h5>
    +  Distribute as a single APK
    +</h5>
    +
    +<p>
    +  It's recommended that you publish your app as a single APK for all screen
    +  sizes (phones and tablets), with a single Google Play listing. This approach
    +  has several important advantages.
    +</p>
    +
    +<ul style="margin-top:.25em;">
    +  <li>Easier for users to find your app from search, browsing, or promotions
    +  </li>
    +
    +  <li>Easier for users to restore your app automatically if they get a new
    +  device.
    +  </li>
    +
    +  <li>Your ratings and download stats are consolidated across all devices.
    +  </li>
    +
    +  <li>Publishing a tablet app in a second listing can dilute ratings for your
    +  brand.
    +  </li>
    +</ul>
    +
    +<p>
    +  If necessary, you can alternatively choose to deliver your app using <a href=
    +  "/google/play/publishing/multiple-apks.html">Multiple APK Support</a>,
    +  although in most cases using a single APK to reach all devices is strongly
    +  recommended.
    +</p>
    +
    +<div class="rel-resources">
    +<h3>Related resources</h3>
    +<ul>
    +<li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
    +      Checklist</a>&mdash;
    +  Recommendations on how to prepare your app for publishing, test it, and launch
    +  successfully on Google Play.</li>
    +<li><a href="https://play.google.com/apps/publish/">Google Play Developer
    +  Console</a>&mdash;The tools console for publishing your app to Android users.</li>
    +</ul>
    +</div>
    +
    +<h2 id="basic-technical-checks">Basic Technical Checks for Tablets</h2>
    +
    +<p>
    +  This section lists specific details on basic technical checks that you should
    +  perform before publishing. The checks ensure that your app is properly targeted to a
    +  broad range of tablet devices. Make sure that the app meets all of the checks
    +  listed below.
    +</p>
    +
    +<p>
    +  To verify the basic technical checks, follow the <a href="#tests">Test
    +  Procedures</a> listed below. Before you start, you need to obtain need the
    +  application source code.
    +</p>
    +
    +<h5 id="criteria">
    +Technical checks
    +</h5>
    +
     <table>
    -<tr>
    -<td><p>Related resources:</p>
    -<ul style="margin-top:-.5em;">
    -<li><strong><a href="https://play.google.com/apps/publish/">Publishing Checklist</a></strong> &mdash; Recommendations on how to prepare your app for publishing, test it, and launch successfully on Google Play.</li>
    -<li><strong><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></strong> &mdash; The tools console for publishing your app to Android users.</li>
    -</ul>
    -</td>
    -</tr>
    +  <tr>
    +    <th style="width:2px;">
    +      Area
    +    </th>
    +    <th style="width:54px;">
    +      ID
    +    </th>
    +    <th>
    +      Description
    +    </th>
    +    <th style="width:54px;">
    +      Tests
    +    </th>
    +  </tr>
    +  <tr id="TB-R1">
    +    <td rowspan="2">Android Versions</td>
    +    <td>
    +      TB-R1
    +    </td>
    +    <td>
    +      <p style="margin-bottom:.5em;">App <em>does</em> target minimum Android versions
    +        that support tablets:</p>
    +      <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
    +        <li><code>targetSdkVersion</code> is declared with value 11 or higher, OR</li>
    +        <li><code>minSdkVersion</code> is declared with value 11 or higher.</li>
    +      </ol>
    +    </td>
    +      <td><a href="#tests">TA-1</a></td>
    +  </tr>
    +  <tr id="TB-R2">
    +    <td>
    +      TB-R2
    +    </td>
    +    <td>
    +      <p style="margin-bottom:.5em;">App <em>does not</em> limit targeting to
    +        exclude Android versions that support tablets:</p>
    +      <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
    +        <li><code>maxSdkVersion</code>, if declared, must have a value of 12
    +          or higher. </li>
    +      </ol>
    +      <p class="caution" style="margin-bottom:.25em;">Note that, in most cases, the use of <code>
    +        maxSdkVersion</code> is not recommended.</p>
    +    </td>
    +    <td><a href="#tests">TA-1</a></td>
    +  </tr>
    +  <tr id="TB-R3">
    +    <td rowspan="1">Feature Dependencies</td>
    +    <td>
    +      TB-R3
    +    </td>
    +    <td>
    +      <p style="margin-bottom:.5em;">App <em>does not</em> limit distribution to
    +        tablets by requiring hardware features not normally available on tablets,
    +        whether <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#declared"
    +        declared explicitly</a> or <a href=
    +        "/guide/topics/manifest/uses-feature-element.html#permissions">implied by
    +        permissions</a>.
    +      </p> 
    +      <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
    +        <li>the app must not declare a <code>&lt;uses-feature&gt;</code> element for
    +          <code>android.hardware.telephony</code> unless the element is specifically
    +          marked with the <code>android:required="false"</code> attribute. 
    +        </li>
    +      </ol>
    +      <p>For details, see <a href="#hardware-requirements">Hardware Requirements</a>
    +        earlier in this document.</p>
    +    </td>
    +    <td><a href="#tests">TA-1</a></td>
    +  </tr>
    +  <tr id="TB-R4">
    +  <td rowspan="2">Screens Support</td>
    +    <td>
    +      TB-R4
    +    </td>
    +    <td>
    +      <p style="margin-bottom:.5em;">App <em>does not</em> limit distribution to common
    +        tablet screen sizes:</p>
    +      <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
    +        <li>If declared, <code>&lt;supports-screens&gt;</code> element must not specify
    +          <code>android:largeScreens="false"</code> or <code>android:xlargeScreens="false"</code>.</li>
    +        <li>For a <code>minSdkVersion</code> value less than 13, a <code>&lt;supports-screens&gt;</code>
    +          element must be declared with both <code>android:largeScreens="true"</code>
    +          and <code>android:xlargeScreens="true"</code>.</li>
    +      </ol>
    +    </td>
    +    <td><a href="#tests">TA-1</a></td>
    +  </tr>
    +  <tr id="TB-R5">
    +    <td>
    +          TB-R5
    +    </td>
    +    <td>
    +      <p style="margin-bottom:.5em;">App <em>does</em> supply custom drawables and
    +        assets for common tablet screen densities. Specifically, the APK must include
    +        corresponding resource directories tagged with these qualifiers:</p>
    +        <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
    +            <li>An <code>hdpi</code> qualifier, OR</li>
    +            <li>An <code>xhdpi</code> qualifier, OR</li>
    +            <li>An <code>xxhdpi</code> qualifier</li>
    +          </ol>
    +
    +          <p>For details, see <a href="#use-tablet-icons">Icons and Other Assets</a>
    +            earlier in this document.</p>
    +      </td>
    +    <td><a href="#tests">TA-2</a></td>
    +  </tr>
     </table>
     
    +<p>If you use <a href="{@docRoot}google/play/publishing/multiple-apks.html">multiple APK
    +  support</a> to deliver size- or version-specific APKs, the APKs and their
    +  characteristics must meet all of the criteria listed above, either individually
    +  or as a cumulative set.</p>
    +
    +<h5 id="tests">
    +  Test procedures
    +</h5>
    +
    +<table>
    +  <tr>
    +    <th style="width:54px;">
    +      Procedure
    +    <th>
    +      Description
    +    </th>
    +  </tr>
    +    <td>
    +         TA-1
    +   </td>
    +    <td>
    +      <p style="margin-bottom:.5em;">Obtain the APK and inspect the manifest.xml file. Check for the required attribute values.</p>
    +    </td>
    +  </tr>
    +  <tr id="ta2">
    +    <td>
    +      TA-2
    +    </td>
    +    <td>
    +      <p style="margin-bottom:.5em;">Obtain the APK and inspect the resources
    +        directories. Make sure that the app includes custom drawables and assets
    +        directories tagged with the required qualifiers.</p>
    +      </td>
    +  </tr>
    +</table>
    +
    +<div class="rel-resources">
    +  <h3>
    +    Related resources
    +  </h3>
    +
    +  <ul>
    +    <li>
    +      <a href="{@docRoot}distribute/googleplay/quality/core.html">Core App
    +      Quality</a>&mdash;A set of core quality criteria that all Android apps
    +      should meet on all targeted devices.
    +    </li>
    +
    +    <li>
    +      <a href="#test-environment">Setting up a Test
    +      Environment</a>&mdash;Information on how to set up an environment to test
    +      your app on tablets.
    +    </li>
    +  </ul>
    +</div>
    +
     <h2 id="test-environment">Setting Up a Test Environment for Tablets</h2>
     
     <p>To assess the quality of your app on tablets &mdash; both for core app quality
    @@ -541,7 +1070,7 @@
     
     <p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
     include one or two devices from each row in the table below, with one of the
    -listed chipsets, platform versions, and hardware feature configurations.</p>
    +listed platform versions, screen configurations, and hardware feature configurations.</p>
     
     <table>
     <tr>
    @@ -556,14 +1085,14 @@
     <td>7-inch tablet</td>
     <td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
     <td><code>hdpi</code>,<br /><code>tvdpi</code></td>
    -<td>Android 4.0+</td>
    +<td>Android 4.0+ (API level 14 and higher)</td>
     <td>WXGA800-7in</td>
     </tr>
     <tr>
     <td><span style="white-space:nowrap">10-inch</span> tablet</td>
     <td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
    -<td><code>mdpi</code>,<br /><code>hdpi</code></td>
    -<td>Android 3.2+</td>
    +<td><code>mdpi</code>,<br /><code>hdpi</code>,<br /><code>xhdpi</code></td>
    +<td>Android 3.2+ (API level 13 and higher)</td>
     <td>WXGA800</td>
     </tr>
     </table>
    \ No newline at end of file
    
    diff --git a/docs/html/google/play/billing/v2/api.jd b/docs/html/google/play/billing/v2/api.jd
    index 9d3a045..7e386a2 100644
    --- a/docs/html/google/play/billing/v2/api.jd
    +++ b/docs/html/google/play/billing/v2/api.jd
    
    @@ -1,4 +1,5 @@
     page.title=In-app Billing Version 2
    +excludeFromSuggestions=true
     @jd:body
     
     <div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
    
    diff --git a/docs/html/google/play/billing/v2/billing_integrate.jd b/docs/html/google/play/billing/v2/billing_integrate.jd
    index defe265..1581315 100644
    --- a/docs/html/google/play/billing/v2/billing_integrate.jd
    +++ b/docs/html/google/play/billing/v2/billing_integrate.jd
    
    @@ -1,4 +1,5 @@
     page.title=Implementing In-app Billing <span style="font-size:16px;">(IAB Version 2)</span>
    +excludeFromSuggestions=true
     @jd:body
     
     <div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
    
    diff --git a/docs/html/google/play/billing/v2/billing_reference.jd b/docs/html/google/play/billing/v2/billing_reference.jd
    index 84576bc..a946295 100644
    --- a/docs/html/google/play/billing/v2/billing_reference.jd
    +++ b/docs/html/google/play/billing/v2/billing_reference.jd
    
    @@ -1,4 +1,5 @@
     page.title=In-app Billing Reference <span style="font-size:16px;">(IAB Version 2)</span>
    +excludeFromSuggestions=true
     @jd:body
     
     <div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
    
    diff --git a/docs/html/google/play/billing/v2/billing_subscriptions.jd b/docs/html/google/play/billing/v2/billing_subscriptions.jd
    index 5e3bd28..3bcf212 100644
    --- a/docs/html/google/play/billing/v2/billing_subscriptions.jd
    +++ b/docs/html/google/play/billing/v2/billing_subscriptions.jd
    
    @@ -1,4 +1,5 @@
     page.title=Implementing Subscriptions  <span style="font-size:16px;">(IAB Version 2)</span>
    +excludeFromSuggestions=true
     @jd:body
     
     <div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">In-app Billing Version 2 is superseded. Please <a href="{@docRoot}google/play/billing/billing_overview.html#migration">migrate to Version 3</a> at your earliest convenience.</div>
    
    diff --git a/docs/html/guide/components/processes-and-threads.jd b/docs/html/guide/components/processes-and-threads.jd
    index 07a2667..1fed712 100644
    --- a/docs/html/guide/components/processes-and-threads.jd
    +++ b/docs/html/guide/components/processes-and-threads.jd
    
    @@ -1,4 +1,6 @@
     page.title=Processes and Threads
    +page.tags="lifecycle","background"
    +
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
    index f917576..a474498 100644
    --- a/docs/html/guide/topics/admin/device-admin.jd
    +++ b/docs/html/guide/topics/admin/device-admin.jd
    
    @@ -1,4 +1,5 @@
     page.title=Device Administration
    +page.tags="devicepolicymanager","policy","security"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/admin/keychain.jd b/docs/html/guide/topics/admin/keychain.jd
    deleted file mode 100644
    index 2ea2408..0000000
    --- a/docs/html/guide/topics/admin/keychain.jd
    +++ /dev/null
    
    @@ -1,4 +0,0 @@
    -page.title=Text and Input
    -@jd:body
    -
    -<p>Add contnet here</p>
    
    diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
    index 93d6c6f..cdbf827 100644
    --- a/docs/html/guide/topics/appwidgets/index.jd
    +++ b/docs/html/guide/topics/appwidgets/index.jd
    
    @@ -1,4 +1,5 @@
     page.title=App Widgets
    +page.tags="home"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/connectivity/bluetooth.jd b/docs/html/guide/topics/connectivity/bluetooth.jd
    index 832b850..1c55d8b 100644
    --- a/docs/html/guide/topics/connectivity/bluetooth.jd
    +++ b/docs/html/guide/topics/connectivity/bluetooth.jd
    
    @@ -1,4 +1,5 @@
     page.title=Bluetooth
    +page.tags="wireless","bluetoothadapter","bluetoothdevice"
     @jd:body
     
     <div id="qv-wrapper"> 
    
    diff --git a/docs/html/guide/topics/connectivity/sip.jd b/docs/html/guide/topics/connectivity/sip.jd
    index a5f0e2e..526eb83 100644
    --- a/docs/html/guide/topics/connectivity/sip.jd
    +++ b/docs/html/guide/topics/connectivity/sip.jd
    
    @@ -1,4 +1,5 @@
     page.title=Session Initiation Protocol
    +page.tags="sipmanager","sipprofile","sipaudiocall","telephony"
     @jd:body
     <div id="qv-wrapper">
     <div id="qv">
    
    diff --git a/docs/html/guide/topics/connectivity/wifip2p.jd b/docs/html/guide/topics/connectivity/wifip2p.jd
    index efb3ac7..2167a0f 100644
    --- a/docs/html/guide/topics/connectivity/wifip2p.jd
    +++ b/docs/html/guide/topics/connectivity/wifip2p.jd
    
    @@ -1,4 +1,5 @@
     page.title=Wi-Fi Direct
    +page.tags="wireless","WifiP2pManager"
     
     @jd:body
     
    
    diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
    index 2603a06..385c116 100644
    --- a/docs/html/guide/topics/data/data-storage.jd
    +++ b/docs/html/guide/topics/data/data-storage.jd
    
    @@ -1,4 +1,5 @@
     page.title=Storage Options
    +page.tags="database","sharedpreferences","sdcard"
     @jd:body
     
     
    
    diff --git a/docs/html/guide/topics/data/install-location.jd b/docs/html/guide/topics/data/install-location.jd
    index 757cd19..2ec0d5a 100644
    --- a/docs/html/guide/topics/data/install-location.jd
    +++ b/docs/html/guide/topics/data/install-location.jd
    
    @@ -1,4 +1,5 @@
     page.title=App Install Location
    +page.tags="sdcard","external"
     @jd:body
     
     
    
    diff --git a/docs/html/guide/topics/graphics/opengl.jd b/docs/html/guide/topics/graphics/opengl.jd
    index 3ec71b2..469eae2 100644
    --- a/docs/html/guide/topics/graphics/opengl.jd
    +++ b/docs/html/guide/topics/graphics/opengl.jd
    
    @@ -1,6 +1,5 @@
     page.title=OpenGL
    -parent.title=Graphics
    -parent.link=index.html
    +page.tags="games"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/graphics/prop-animation.jd b/docs/html/guide/topics/graphics/prop-animation.jd
    index 49d7bb8..22bf769 100644
    --- a/docs/html/guide/topics/graphics/prop-animation.jd
    +++ b/docs/html/guide/topics/graphics/prop-animation.jd
    
    @@ -1,6 +1,5 @@
     page.title=Property Animation
    -parent.title=Animation
    -parent.link=animation.html
    +page.tags="valueanimator","objectanimator","layouttransition","ViewPropertyAnimator"
     @jd:body
     
       <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/location/strategies.jd b/docs/html/guide/topics/location/strategies.jd
    index 6cc8f1a..2f7e6c3 100644
    --- a/docs/html/guide/topics/location/strategies.jd
    +++ b/docs/html/guide/topics/location/strategies.jd
    
    @@ -1,6 +1,5 @@
     page.title=Location Strategies
    -parent.title=Location and Maps
    -parent.link=index.html
    +page.tags="geolocation","maps","mapview"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/media/audio-capture.jd b/docs/html/guide/topics/media/audio-capture.jd
    index 75d294b..44c618f 100644
    --- a/docs/html/guide/topics/media/audio-capture.jd
    +++ b/docs/html/guide/topics/media/audio-capture.jd
    
    @@ -1,6 +1,5 @@
     page.title=Audio Capture
    -parent.title=Multimedia and Camera 
    -parent.link=index.html
    +page.tags="mediarecorder"
     @jd:body
     
         <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd
    index 3fe23f8..8ebb349 100644
    --- a/docs/html/guide/topics/media/camera.jd
    +++ b/docs/html/guide/topics/media/camera.jd
    
    @@ -1,6 +1,5 @@
     page.title=Camera
    -parent.title=Multimedia and Camera
    -parent.link=index.html
    +page.tags="mediarecorder"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/media/mediaplayer.jd b/docs/html/guide/topics/media/mediaplayer.jd
    index 45a58a7..fb272d2 100644
    --- a/docs/html/guide/topics/media/mediaplayer.jd
    +++ b/docs/html/guide/topics/media/mediaplayer.jd
    
    @@ -1,6 +1,5 @@
     page.title=Media Playback
    -parent.title=Multimedia and Camera 
    -parent.link=index.html
    +page.tags="mediaplayer","soundpool","audiomanager"
     @jd:body
     
         <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/resources/runtime-changes.jd b/docs/html/guide/topics/resources/runtime-changes.jd
    index 5f39aa5..45a548a 100644
    --- a/docs/html/guide/topics/resources/runtime-changes.jd
    +++ b/docs/html/guide/topics/resources/runtime-changes.jd
    
    @@ -1,6 +1,5 @@
     page.title=Handling Runtime Changes
    -parent.title=Application Resources
    -parent.link=index.html
    +page.tags="activity","lifecycle"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/search/adding-custom-suggestions.jd b/docs/html/guide/topics/search/adding-custom-suggestions.jd
    index 02ee084..47ad2fe 100644
    --- a/docs/html/guide/topics/search/adding-custom-suggestions.jd
    +++ b/docs/html/guide/topics/search/adding-custom-suggestions.jd
    
    @@ -1,6 +1,5 @@
     page.title=Adding Custom Suggestions
    -parent.title=Search
    -parent.link=index.html
    +page.tags="SearchRecentSuggestionsProvider",
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/search/adding-recent-query-suggestions.jd b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
    index 2c9a461..c1d59d4 100644
    --- a/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
    +++ b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
    
    @@ -1,6 +1,6 @@
     page.title=Adding Recent Query Suggestions
    -parent.title=Search
    -parent.link=index.html
    +page.tags="SearchRecentSuggestions","SearchRecentSuggestionsProvider"
    +
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
    index e24681a..fc722b2 100644
    --- a/docs/html/guide/topics/search/search-dialog.jd
    +++ b/docs/html/guide/topics/search/search-dialog.jd
    
    @@ -1,6 +1,5 @@
     page.title=Creating a Search Interface
    -parent.title=Search
    -parent.link=index.html
    +page.tags="searchview"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/search/searchable-config.jd b/docs/html/guide/topics/search/searchable-config.jd
    index fb689f9..fc13c04 100644
    --- a/docs/html/guide/topics/search/searchable-config.jd
    +++ b/docs/html/guide/topics/search/searchable-config.jd
    
    @@ -1,6 +1,5 @@
     page.title=Searchable Configuration
    -parent.title=Search
    -parent.link=index.html
    +
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/sensors/sensors_motion.jd b/docs/html/guide/topics/sensors/sensors_motion.jd
    index b6c3cb4..289c639 100644
    --- a/docs/html/guide/topics/sensors/sensors_motion.jd
    +++ b/docs/html/guide/topics/sensors/sensors_motion.jd
    
    @@ -1,6 +1,5 @@
     page.title=Motion Sensors
    -parent.title=Sensors
    -parent.link=index.html
    +page.tags="sensorevent","accelerometer","gyroscope","gravity","rotation"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/sensors/sensors_position.jd b/docs/html/guide/topics/sensors/sensors_position.jd
    index 869109b..55b282b 100644
    --- a/docs/html/guide/topics/sensors/sensors_position.jd
    +++ b/docs/html/guide/topics/sensors/sensors_position.jd
    
    @@ -1,6 +1,5 @@
     page.title=Position Sensors
    -parent.title=Sensors
    -parent.link=index.html
    +page.tags="sensorevent","orientation","proximity"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/text/copy-paste.jd b/docs/html/guide/topics/text/copy-paste.jd
    index 6c86f47..b34f0fa 100644
    --- a/docs/html/guide/topics/text/copy-paste.jd
    +++ b/docs/html/guide/topics/text/copy-paste.jd
    
    @@ -1,4 +1,5 @@
     page.title=Copy and Paste
    +page.tags="clipboardmanager","clipdata","input"
     @jd:body
     <div id="qv-wrapper">
         <div id="qv">
    
    diff --git a/docs/html/guide/topics/text/creating-input-method.jd b/docs/html/guide/topics/text/creating-input-method.jd
    index 7086824..7254594 100644
    --- a/docs/html/guide/topics/text/creating-input-method.jd
    +++ b/docs/html/guide/topics/text/creating-input-method.jd
    
    @@ -1,5 +1,5 @@
     page.title=Creating an Input Method
    -parent.title=Articles
    +page.tags="ime","keyboard","inputmethodservice"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/text/spell-checker-framework.jd b/docs/html/guide/topics/text/spell-checker-framework.jd
    index 7f7a0b8..366f9cc 100644
    --- a/docs/html/guide/topics/text/spell-checker-framework.jd
    +++ b/docs/html/guide/topics/text/spell-checker-framework.jd
    
    @@ -1,5 +1,5 @@
     page.title=Spelling Checker Framework
    -parent.title=Articles
    +page.tags="input","spellcheckerservice"
     @jd:body
     <div id="qv-wrapper">
     <div id="qv">
    
    diff --git a/docs/html/guide/topics/ui/controls/button.jd b/docs/html/guide/topics/ui/controls/button.jd
    index 8d48e9c..41b67b7f 100644
    --- a/docs/html/guide/topics/ui/controls/button.jd
    +++ b/docs/html/guide/topics/ui/controls/button.jd
    
    @@ -1,6 +1,5 @@
     page.title=Buttons
    -parent.title=Input Controls
    -parent.link=../controls.html
    +page.tags="button","imagebutton"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/controls/checkbox.jd b/docs/html/guide/topics/ui/controls/checkbox.jd
    index ea70980..99140b5 100644
    --- a/docs/html/guide/topics/ui/controls/checkbox.jd
    +++ b/docs/html/guide/topics/ui/controls/checkbox.jd
    
    @@ -1,6 +1,5 @@
     page.title=Checkboxes
    -parent.title=Input Controls
    -parent.link=../controls.html
    +
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/controls/pickers.jd b/docs/html/guide/topics/ui/controls/pickers.jd
    index cf90f1d..a0e7afb 100644
    --- a/docs/html/guide/topics/ui/controls/pickers.jd
    +++ b/docs/html/guide/topics/ui/controls/pickers.jd
    
    @@ -1,6 +1,5 @@
    -page.title= Pickers
    -parent.title=Form Controls
    -parent.link=controls-form.html
    +page.title=Pickers
    +page.tags="datepicker","timepicker"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/controls/radiobutton.jd b/docs/html/guide/topics/ui/controls/radiobutton.jd
    index c96e576..d0c48ed 100644
    --- a/docs/html/guide/topics/ui/controls/radiobutton.jd
    +++ b/docs/html/guide/topics/ui/controls/radiobutton.jd
    
    @@ -1,6 +1,5 @@
     page.title=Radio Buttons
    -parent.title=Input Controls
    -parent.link=../controls.html
    +page.tags="radiobutton","radiogroup"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/controls/spinner.jd b/docs/html/guide/topics/ui/controls/spinner.jd
    index deba3e6..85714b6 100644
    --- a/docs/html/guide/topics/ui/controls/spinner.jd
    +++ b/docs/html/guide/topics/ui/controls/spinner.jd
    
    @@ -1,6 +1,5 @@
    -page.title= Spinners
    -parent.title=Input Controls
    -parent.link=../controls.html
    +page.title=Spinners
    +page.tags="adapterview","spinneradapter"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/controls/text.jd b/docs/html/guide/topics/ui/controls/text.jd
    index 654883d..c0b9873 100644
    --- a/docs/html/guide/topics/ui/controls/text.jd
    +++ b/docs/html/guide/topics/ui/controls/text.jd
    
    @@ -1,6 +1,5 @@
     page.title=Text Fields
    -parent.title=Input Controls
    -parent.link=../controls.html
    +page.tags="edittext","autocompletetextview"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/controls/togglebutton.jd b/docs/html/guide/topics/ui/controls/togglebutton.jd
    index dd7634b..3119cd9 100644
    --- a/docs/html/guide/topics/ui/controls/togglebutton.jd
    +++ b/docs/html/guide/topics/ui/controls/togglebutton.jd
    
    @@ -1,6 +1,5 @@
     page.title=Toggle Buttons
    -parent.title=Input Controls
    -parent.link=../controls.html
    +page.tags="switch","togglebutton"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/custom-components.jd b/docs/html/guide/topics/ui/custom-components.jd
    index be82dbc..703a5ce 100644
    --- a/docs/html/guide/topics/ui/custom-components.jd
    +++ b/docs/html/guide/topics/ui/custom-components.jd
    
    @@ -1,6 +1,5 @@
     page.title=Custom Components
    -parent.title=User Interface
    -parent.link=index.html
    +page.tags="view","widget"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
    index 28e1418..6398646 100644
    --- a/docs/html/guide/topics/ui/declaring-layout.jd
    +++ b/docs/html/guide/topics/ui/declaring-layout.jd
    
    @@ -1,6 +1,5 @@
     page.title=Layouts
    -parent.title=User Interface
    -parent.link=index.html
    +page.tags="view","viewgroup"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
    index 3cfed13..7f48eac 100644
    --- a/docs/html/guide/topics/ui/dialogs.jd
    +++ b/docs/html/guide/topics/ui/dialogs.jd
    
    @@ -1,4 +1,6 @@
     page.title=Dialogs
    +page.tags="alertdialog","dialogfragment"
    +
     @jd:body
     
     
    
    diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd
    index 884a1b2..e989374 100644
    --- a/docs/html/guide/topics/ui/drag-drop.jd
    +++ b/docs/html/guide/topics/ui/drag-drop.jd
    
    @@ -1,6 +1,5 @@
     page.title=Drag and Drop
    -parent.title=User Interface
    -parent.link=index.html
    +page.tags="clipdata","dragevent","onlongclicklistener"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/layout/gridview.jd b/docs/html/guide/topics/ui/layout/gridview.jd
    index 84c3dab..bc189c4 100644
    --- a/docs/html/guide/topics/ui/layout/gridview.jd
    +++ b/docs/html/guide/topics/ui/layout/gridview.jd
    
    @@ -1,6 +1,5 @@
     page.title=Grid View
    -parent.title=Layouts
    -parent.link=layout-objects.html
    +page.tags="gridview"
     @jd:body
     <div id="qv-wrapper">
     <div id="qv">
    
    diff --git a/docs/html/guide/topics/ui/layout/linear.jd b/docs/html/guide/topics/ui/layout/linear.jd
    index 8e33706..444dc71 100644
    --- a/docs/html/guide/topics/ui/layout/linear.jd
    +++ b/docs/html/guide/topics/ui/layout/linear.jd
    
    @@ -1,6 +1,5 @@
     page.title=Linear Layout
    -parent.title=Layouts
    -parent.link=layout-objects.html
    +page.tags="linearlayout"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/layout/listview.jd b/docs/html/guide/topics/ui/layout/listview.jd
    index fee5292..6cdd725 100644
    --- a/docs/html/guide/topics/ui/layout/listview.jd
    +++ b/docs/html/guide/topics/ui/layout/listview.jd
    
    @@ -1,6 +1,5 @@
     page.title=List View
    -parent.title=Layouts
    -parent.link=declaring-layout.html
    +page.tags="listview"
     @jd:body
     <div id="qv-wrapper">
     <div id="qv">
    
    diff --git a/docs/html/guide/topics/ui/layout/relative.jd b/docs/html/guide/topics/ui/layout/relative.jd
    index 47f9417..65c5617 100644
    --- a/docs/html/guide/topics/ui/layout/relative.jd
    +++ b/docs/html/guide/topics/ui/layout/relative.jd
    
    @@ -1,6 +1,5 @@
     page.title=Relative Layout
    -parent.title=Layouts
    -parent.link=layout-objects.html
    +page.tags="relativelayout"
     @jd:body
     
     <div id="qv-wrapper">
    
    diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd
    index 33e164b..d96447d 100644
    --- a/docs/html/guide/topics/ui/settings.jd
    +++ b/docs/html/guide/topics/ui/settings.jd
    
    @@ -1,4 +1,6 @@
     page.title=Settings
    +page.tags="preference","preferenceactivity","preferencefragment"
    +
     @jd:body
     
     
    
    diff --git a/docs/html/images/example-bad.png b/docs/html/images/example-bad.png
    new file mode 100644
    index 0000000..b19a9f7
    --- /dev/null
    +++ b/docs/html/images/example-bad.png
    Binary files differ
    
    diff --git a/docs/html/images/example-good.png b/docs/html/images/example-good.png
    new file mode 100644
    index 0000000..6bd2408
    --- /dev/null
    +++ b/docs/html/images/example-good.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ads-eula-violation.png b/docs/html/images/gp-policy-ads-eula-violation.png
    new file mode 100644
    index 0000000..e8ffa5b
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ads-eula-violation.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ads-eula.png b/docs/html/images/gp-policy-ads-eula.png
    new file mode 100644
    index 0000000..68a6b95
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ads-eula.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ads-impersonate-violation.png b/docs/html/images/gp-policy-ads-impersonate-violation.png
    new file mode 100644
    index 0000000..385ae6e
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ads-impersonate-violation.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ads-maturity-violation.png b/docs/html/images/gp-policy-ads-maturity-violation.png
    new file mode 100644
    index 0000000..d41870e
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ads-maturity-violation.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ads-notif-attr-violation.png b/docs/html/images/gp-policy-ads-notif-attr-violation.png
    new file mode 100644
    index 0000000..af53f10
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ads-notif-attr-violation.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ads-notif-attr.png b/docs/html/images/gp-policy-ads-notif-attr.png
    new file mode 100644
    index 0000000..4934d21
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ads-notif-attr.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ads-paywall-violation.png b/docs/html/images/gp-policy-ads-paywall-violation.png
    new file mode 100644
    index 0000000..8bbfd1b
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ads-paywall-violation.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ads-paywall.png b/docs/html/images/gp-policy-ads-paywall.png
    new file mode 100644
    index 0000000..e7b1e19
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ads-paywall.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ads-terms.png b/docs/html/images/gp-policy-ads-terms.png
    new file mode 100644
    index 0000000..dcbdf4a
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ads-terms.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ip-copyright-violation.png b/docs/html/images/gp-policy-ip-copyright-violation.png
    new file mode 100644
    index 0000000..a4e96a8
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ip-copyright-violation.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ip-impersonation-violation.png b/docs/html/images/gp-policy-ip-impersonation-violation.png
    new file mode 100644
    index 0000000..b1d9923
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ip-impersonation-violation.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-ip-trademark-violation.png b/docs/html/images/gp-policy-ip-trademark-violation.png
    new file mode 100644
    index 0000000..c05b67b
    --- /dev/null
    +++ b/docs/html/images/gp-policy-ip-trademark-violation.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-spam-negreview.png b/docs/html/images/gp-policy-spam-negreview.png
    new file mode 100644
    index 0000000..f68eba3
    --- /dev/null
    +++ b/docs/html/images/gp-policy-spam-negreview.png
    Binary files differ
    
    diff --git a/docs/html/images/gp-policy-spam-reqrating.png b/docs/html/images/gp-policy-spam-reqrating.png
    new file mode 100644
    index 0000000..aaf9e53
    --- /dev/null
    +++ b/docs/html/images/gp-policy-spam-reqrating.png
    Binary files differ
    
    diff --git a/docs/html/sdk/1.0_r1/index.jd b/docs/html/sdk/1.0_r1/index.jd
    index b380483..dea6620 100644
    --- a/docs/html/sdk/1.0_r1/index.jd
    +++ b/docs/html/sdk/1.0_r1/index.jd
    
    @@ -1,5 +1,6 @@
     page.title=Android 1.0 SDK, release 1
     sdk.redirect=true
     sdk.redirect.path=index.html
    +excludeFromSuggestions=true
     
     @jd:body
    
    diff --git a/docs/html/sdk/1.0_r1/upgrading.jd b/docs/html/sdk/1.0_r1/upgrading.jd
    index d6d5dc4..d6a7ed5 100644
    --- a/docs/html/sdk/1.0_r1/upgrading.jd
    +++ b/docs/html/sdk/1.0_r1/upgrading.jd
    
    @@ -1,5 +1,6 @@
     page.title=Upgrading the SDK
     sdk.version=1.0_r1
    +excludeFromSuggestions=true
     @jd:body
     
     <p>For the current SDK release, see the links under <strong>Current SDK Release</strong> in the side navigation.</p>
    
    diff --git a/docs/html/sdk/1.0_r2/index.jd b/docs/html/sdk/1.0_r2/index.jd
    index c29c148..8556e3c 100644
    --- a/docs/html/sdk/1.0_r2/index.jd
    +++ b/docs/html/sdk/1.0_r2/index.jd
    
    @@ -1,5 +1,6 @@
     page.title=Android 1.0 SDK, release 2
     sdk.redirect=true
     sdk.redirect.path=index.html
    +excludeFromSuggestions=true
     
     @jd:body
    
    diff --git a/docs/html/sdk/1.0_r2/upgrading.jd b/docs/html/sdk/1.0_r2/upgrading.jd
    index 409e30e..243950d 100644
    --- a/docs/html/sdk/1.0_r2/upgrading.jd
    +++ b/docs/html/sdk/1.0_r2/upgrading.jd
    
    @@ -1,5 +1,6 @@
     page.title=Upgrading the SDK
     sdk.version=1.0_r2
    +excludeFromSuggestions=true
     @jd:body
     
     <p>For the current SDK release, see the links under <strong>Current SDK Release</strong> in the side navigation.</p>
    
    diff --git a/docs/html/sdk/1.1_r1/index.jd b/docs/html/sdk/1.1_r1/index.jd
    index 63fe51d..44231ee 100644
    --- a/docs/html/sdk/1.1_r1/index.jd
    +++ b/docs/html/sdk/1.1_r1/index.jd
    
    @@ -1,5 +1,6 @@
     page.title=Android 1.1 SDK, Release 1
     sdk.redirect=true
     sdk.redirect.path=index.html
    +excludeFromSuggestions=true
     
     @jd:body
    
    diff --git a/docs/html/sdk/1.1_r1/upgrading.jd b/docs/html/sdk/1.1_r1/upgrading.jd
    index bc71149..840ae6b 100644
    --- a/docs/html/sdk/1.1_r1/upgrading.jd
    +++ b/docs/html/sdk/1.1_r1/upgrading.jd
    
    @@ -1,5 +1,6 @@
     page.title=Upgrading the SDK
     sdk.version=1.1_r1
    +excludeFromSuggestions=true
     @jd:body
     
     <!--
    
    diff --git a/docs/html/sdk/1.5_r1/index.jd b/docs/html/sdk/1.5_r1/index.jd
    index 60dfc14..7232f57 100644
    --- a/docs/html/sdk/1.5_r1/index.jd
    +++ b/docs/html/sdk/1.5_r1/index.jd
    
    @@ -1,5 +1,6 @@
     page.title=Android 1.5 SDK, Release 1
     sdk.redirect=true
     sdk.redirect.path=index.html
    +excludeFromSuggestions=true
     
     @jd:body
    
    diff --git a/docs/html/sdk/1.5_r1/upgrading.jd b/docs/html/sdk/1.5_r1/upgrading.jd
    index 0a12d62..0377069 100644
    --- a/docs/html/sdk/1.5_r1/upgrading.jd
    +++ b/docs/html/sdk/1.5_r1/upgrading.jd
    
    @@ -1,5 +1,6 @@
     page.title=Upgrading the SDK
     sdk.version=1.5_r1
    +excludeFromSuggestions=true
     @jd:body
     
     
    
    diff --git a/docs/html/sdk/1.5_r2/index.jd b/docs/html/sdk/1.5_r2/index.jd
    index 4fb99b6..fac4f13 100644
    --- a/docs/html/sdk/1.5_r2/index.jd
    +++ b/docs/html/sdk/1.5_r2/index.jd
    
    @@ -1,5 +1,6 @@
     page.title=Android 1.5 SDK, Release 2
     sdk.redirect=true
     sdk.redirect.path=index.html
    +excludeFromSuggestions=true
     
     @jd:body
    
    diff --git a/docs/html/sdk/1.5_r2/upgrading.jd b/docs/html/sdk/1.5_r2/upgrading.jd
    index bb5fc60..31b2358 100644
    --- a/docs/html/sdk/1.5_r2/upgrading.jd
    +++ b/docs/html/sdk/1.5_r2/upgrading.jd
    
    @@ -1,5 +1,6 @@
     page.title=Upgrading the SDK
     sdk.version=1.5_r2
    +excludeFromSuggestions=true
     @jd:body
     
     
    
    diff --git a/docs/html/sdk/1.5_r3/index.jd b/docs/html/sdk/1.5_r3/index.jd
    index eb10f5e..e8cfaa1 100644
    --- a/docs/html/sdk/1.5_r3/index.jd
    +++ b/docs/html/sdk/1.5_r3/index.jd
    
    @@ -1,5 +1,6 @@
     page.title=Android 1.5 SDK, Release 3
     sdk.redirect=true
     sdk.redirect.path=index.html
    +excludeFromSuggestions=true
     
     @jd:body
    
    diff --git a/docs/html/sdk/1.5_r3/upgrading.jd b/docs/html/sdk/1.5_r3/upgrading.jd
    index 18c1314..62b9a78 100644
    --- a/docs/html/sdk/1.5_r3/upgrading.jd
    +++ b/docs/html/sdk/1.5_r3/upgrading.jd
    
    @@ -1,6 +1,7 @@
     page.title=Upgrading the SDK
     sdk.version=1.5
     sdk.rel.id=3
    +excludeFromSuggestions=true
     
     @jd:body
     
    
    diff --git a/docs/html/sdk/1.6_r1/index.jd b/docs/html/sdk/1.6_r1/index.jd
    index e7f9112..671d1cd 100644
    --- a/docs/html/sdk/1.6_r1/index.jd
    +++ b/docs/html/sdk/1.6_r1/index.jd
    
    @@ -1,5 +1,6 @@
     page.title=Android 1.6 SDK, Release 1
     sdk.redirect=true
     sdk.redirect.path=index.html
    +excludeFromSuggestions=true
     
     @jd:body
    
    diff --git a/docs/html/sdk/1.6_r1/upgrading.jd b/docs/html/sdk/1.6_r1/upgrading.jd
    index 49535c9..e6dded0 100644
    --- a/docs/html/sdk/1.6_r1/upgrading.jd
    +++ b/docs/html/sdk/1.6_r1/upgrading.jd
    
    @@ -1,5 +1,6 @@
     page.title=Upgrading the SDK
     sdk.version=1.6
    +excludeFromSuggestions=true
     @jd:body
     
     
    
    diff --git a/docs/html/support.jd b/docs/html/support.jd
    index 89acd5d..86427b4 100644
    --- a/docs/html/support.jd
    +++ b/docs/html/support.jd
    
    @@ -46,7 +46,7 @@
     
     <h5 id="contact">Direct support contacts for developers</h5>
     <p style="color:#888">
    -  <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=dev_registration">Registration, account issues</a><br />
    +  <a href=" https://support.google.com/googleplay/android-developer/troubleshooter/3049653">Registration, account issues</a><br />
       <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=publishing">Publishing, app distribution issues</a><br />
       <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=bugs">Developer Console issues</a><br />
       <a href="http://support.google.com/googleplay/android-developer/bin/request.py?contact_type=takedown">Inappropriate apps</a><br />
    
    diff --git a/docs/html/tools/extras/oem-usb.jd b/docs/html/tools/extras/oem-usb.jd
    index 774fe87..87734a1 100644
    --- a/docs/html/tools/extras/oem-usb.jd
    +++ b/docs/html/tools/extras/oem-usb.jd
    
    @@ -306,6 +306,10 @@
     <tr><td>MTK</td> <td><a
     href="http://online.mediatek.com/Public%20Documents/MTK_Android_USB_Driver.zip">http://online.mediatek.com/Public%20Documents/MTK_Android_USB_Driver.zip</a></td>
     </tr>
    +<tr><td>Oppo</td> <td><a
    +href="http://www.oppo.com/index.php?q=software/view&sw_id=631"
    +>http://www.oppo.com/index.php?q=software/view&sw_id=631</a></td>
    +</tr>
     <tr><td>Pantech</td>	<td><a
     href="http://www.isky.co.kr/cs/software/software.sky?fromUrl=index">http://www.isky.co.kr/cs/software/software.sky?fromUrl=index</a></td>
     </tr><tr><td>Pegatron</td>	<td><a
    @@ -327,6 +331,9 @@
     href="http://www.yulong.com/product/product/product/downloadList.html#downListUL">http://www.yulong.com/product/product/product/downloadList.html#downListUL</a></td>
     </tr>
     
    +<tr><td>Xiaomi</td>  <td><a
    +href="http://www.xiaomi.com/c/driver/index.html">http://www.xiaomi.com/c/driver/index.html</a></td>
    +</tr>
     <tr>
     <td>ZTE</td>	<td><a
     href="http://support.zte.com.cn/support/news/NewsDetail.aspx?newsId=1000442">http://support.zte.com.cn/support/news/NewsDetail.aspx?newsId=1000442</a></td></tr>
    
    diff --git a/docs/html/tools/sdk/OLD_RELEASENOTES.jd b/docs/html/tools/sdk/OLD_RELEASENOTES.jd
    index 6865db2..b7fd12f 100644
    --- a/docs/html/tools/sdk/OLD_RELEASENOTES.jd
    +++ b/docs/html/tools/sdk/OLD_RELEASENOTES.jd
    
    @@ -1,4 +1,5 @@
     page.title=Release Notes for Older SDK Versions
    +excludeFromSuggestions=true
     @jd:body
     
     <div class="special">
    
    diff --git a/docs/html/tools/sdk/RELEASENOTES.jd b/docs/html/tools/sdk/RELEASENOTES.jd
    index c7ece42..cbcbb12 100644
    --- a/docs/html/tools/sdk/RELEASENOTES.jd
    +++ b/docs/html/tools/sdk/RELEASENOTES.jd
    
    @@ -1,4 +1,5 @@
     page.title=SDK Release Notes
    +excludeFromSuggestions=true
     @jd:body
     
     <p>This document provides version-specific information about Android SDK
    
    diff --git a/docs/html/tools/sdk/addons.jd b/docs/html/tools/sdk/addons.jd
    deleted file mode 100644
    index 8c5e1ed..0000000
    --- a/docs/html/tools/sdk/addons.jd
    +++ /dev/null
    
    @@ -1,9 +0,0 @@
    -page.title=SDK Add-Ons
    -
    -@jd:body
    -
    -
    -
    -<p>A page that lists SDK addons and links to release notes. Links to dashboards etc.</p>
    -
    -
    
    diff --git a/docs/html/tools/sdk/adt-notes.jd b/docs/html/tools/sdk/adt-notes.jd
    deleted file mode 100644
    index 291b543..0000000
    --- a/docs/html/tools/sdk/adt-notes.jd
    +++ /dev/null
    
    @@ -1,5 +0,0 @@
    -page.title=ADT Plugin for Eclipse
    -sdk.redirect=true
    -sdk.redirect.path=eclipse-adt.html
    -
    -@jd:body
    
    diff --git a/docs/html/tools/sdk/adt_download.html b/docs/html/tools/sdk/adt_download.html
    deleted file mode 100644
    index 5ba2ef5..0000000
    --- a/docs/html/tools/sdk/adt_download.html
    +++ /dev/null
    
    @@ -1,10 +0,0 @@
    -<html>
    -<head>
    -<meta http-equiv="refresh" content="0;url=http://developer.android.com/sdk/eclipse-adt.html">
    -<title>Redirecting...</title>
    -</head>
    -<body>
    -<p>You should be redirected. Please <a
    -href="http://developer.android.com/sdk/eclipse-adt.html">click here</a>.</p>
    -</body>
    -</html>
    \ No newline at end of file
    
    diff --git a/docs/html/tools/sdk/libraries.jd b/docs/html/tools/sdk/libraries.jd
    deleted file mode 100644
    index 9e47c4a..0000000
    --- a/docs/html/tools/sdk/libraries.jd
    +++ /dev/null
    
    @@ -1,9 +0,0 @@
    -page.title=Libraries
    -
    -@jd:body
    -
    -
    -
    -<p>A page that lists libraries and links to release notes. Links to dashboards etc.</p>
    -
    -
    
    diff --git a/docs/html/tools/sdk/ndk/1.5_r1/index.jd b/docs/html/tools/sdk/ndk/1.5_r1/index.jd
    index 4c70a8a..2f6764b 100644
    --- a/docs/html/tools/sdk/ndk/1.5_r1/index.jd
    +++ b/docs/html/tools/sdk/ndk/1.5_r1/index.jd
    
    @@ -1,6 +1,7 @@
     page.title=Android 1.5 NDK, Release 1
     sdk.redirect=true
     sdk.redirect.path=ndk/index.html
    +excludeFromSuggestions=true
     
     @jd:body
     
    
    diff --git a/docs/html/tools/sdk/ndk/1.6_r1/index.jd b/docs/html/tools/sdk/ndk/1.6_r1/index.jd
    index 090dcdc..1dc5b6f 100644
    --- a/docs/html/tools/sdk/ndk/1.6_r1/index.jd
    +++ b/docs/html/tools/sdk/ndk/1.6_r1/index.jd
    
    @@ -1,5 +1,6 @@
     page.title=Android 1.6 NDK, Release 1
     sdk.redirect=true
     sdk.redirect.path=ndk/index.html
    +excludeFromSuggestions=true
     
     @jd:body
    
    diff --git a/docs/html/tools/sdk/ndk/overview.jd b/docs/html/tools/sdk/ndk/overview.jd
    deleted file mode 100644
    index 98ef1fc..0000000
    --- a/docs/html/tools/sdk/ndk/overview.jd
    +++ /dev/null
    
    @@ -1,588 +0,0 @@
    -page.title=What is the NDK?
    -@jd:body
    -
    - <div id="qv-wrapper">
    -    <div id="qv">
    -      <h2>In this document</h2>
    -
    -      <ol>
    -        <li><a href="#choosing">When to Develop in Native Code</a></li>
    -        <li>
    -          <a href="#contents">Contents of the NDK</a>
    -          <ol>
    -            <li><a href="#tools">Development tools</a></li>
    -
    -            <li><a href="#docs">Documentation</a></li>
    -
    -            <li><a href="#samples">Sample applications</a></li>
    -          </ol>
    -        </li>
    -        <li><a href="#reqs">System and Software Requirements</a></li>
    -      </ol>
    -    </div>
    -  </div>
    -
    -  <p>The Android NDK is a toolset that lets you embed components that make use of native code in
    -  your Android applications.</p>
    -
    -  <p>Android applications run in the Dalvik virtual machine. The NDK allows you to implement parts
    -  of your applications using native-code languages such as C and C++. This can provide benefits to
    -  certain classes of applications, in the form of reuse of existing code and in some cases
    -  increased speed.</p>
    -
    -  <p>The NDK provides:</p>
    -
    -  <ul>
    -    <li>A set of tools and build files used to generate native code libraries from C and C++
    -    sources</li>
    -
    -    <li>A way to embed the corresponding native libraries into an application package file
    -    (<code>.apk</code>) that can be deployed on Android devices</li>
    -
    -    <li>A set of native system headers and libraries that will be supported in all future versions
    -    of the Android platform, starting from Android 1.5. Applications that use native activities
    -    must be run on Android 2.3 or later.</li>
    -
    -    <li>Documentation, samples, and tutorials</li>
    -  </ul>
    -
    -  <p>The latest release of the NDK supports the following instruction sets:</p>
    -
    -  <ul>
    -    <li>ARMv5TE, including Thumb-1 instructions (see {@code docs/CPU-ARCH-ABIS.html} for more
    -information)</li>
    -
    -    <li>ARMv7-A, including Thumb-2 and VFPv3-D16 instructions, with optional support for
    -    NEON/VFPv3-D32 instructions (see {@code docs/CPU-ARM-NEON.html} for more information)</li>
    -
    -    <li>x86 instructions (see {@code docs/CPU-X86.html} for more information)</li>
    -
    -    <li>MIPS instructions (see {@code docs/CPU-MIPS.html} for more information)</li>
    -  </ul>
    -
    -  <p>ARMv5TE machine code will run on all ARM-based Android devices. ARMv7-A will run only on
    -  devices such as the Verizon Droid or Google Nexus One that have a compatible CPU. The main
    -  difference between the two instruction sets is that ARMv7-A supports hardware FPU, Thumb-2, and
    -  NEON instructions. You can target either or both of the instruction sets &mdash; ARMv5TE is the
    -  default, but switching to ARMv7-A is as easy as adding a single line to the application's
    -  <code>Application.mk</code> file, without needing to change anything else in the file. You can also build for
    -  both architectures at the same time and have everything stored in the final <code>.apk</code>.
    -  Complete information is provided in the CPU-ARCH-ABIS.HTML in the NDK package.</p>
    -
    -  <p>The NDK provides stable headers for libc (the C library), libm (the Math library), OpenGL ES
    -  (3D graphics library), the JNI interface, and other libraries, as listed in the <a href=
    -  "#tools">Development Tools</a> section.</p>
    -
    -  <h2 id="choosing">When to Develop in Native Code</h2>
    -
    -  <p>The NDK will not benefit most applications. As a developer, you need to balance its benefits
    -  against its drawbacks; notably, using native code does not result in an automatic performance
    -  increase, but always increases application complexity. In general, you should only use native
    -  code if it is essential to your application, not just because you prefer to program in C/C++.</p>
    -
    -  <p>Typical good candidates for the NDK are self-contained, CPU-intensive operations that don't
    -  allocate much memory, such as signal processing, physics simulation, and so on. Simply re-coding
    -  a method to run in C usually does not result in a large performance increase. When examining
    -  whether or not you should develop in native code, think about your requirements and see if the
    -  Android framework APIs provide the functionality that you need. The NDK can, however, can be an
    -  effective way to reuse a large corpus of existing C/C++ code.</p>
    -
    -  <p>The Android framework provides two ways to use native code:</p>
    -
    -  <ul>
    -    <li>Write your application using the Android framework and use JNI to access the APIs provided
    -    by the Android NDK. This technique allows you to take advantage of the convenience of the
    -    Android framework, but still allows you to write native code when necessary. If you use this
    -    approach, your application must target specific, minimum Android platform levels, see <a
    -    href="#platform-compat">Android platform compatibility</a> for more information.</li>
    -
    -    <li>
    -      <p>Write a native activity, which allows you to implement the lifecycle callbacks in native
    -      code. The Android SDK provides the {@link android.app.NativeActivity} class, which is a
    -      convenience class that notifies your
    -      native code of any activity lifecycle callbacks (<code>onCreate()</code>, <code>onPause()</code>,
    -      <code>onResume()</code>, etc). You can implement the callbacks in your native code to handle
    -      these events when they occur. Applications that use native activities must be run on Android
    -      2.3 (API Level 9) or later.</p>
    -
    -      <p>You cannot access features such as Services and Content Providers natively, so if you want
    -      to use them or any other framework API, you can still write JNI code to do so.</p>
    -    </li>
    -  </ul>
    -
    -  <h2 id="contents">Contents of the NDK</h2>The NDK contains the APIs, documentation, and sample
    -  applications that help you write your native code.
    -
    -  <h3 id="tools">Development tools</h3>
    -
    -  <p>The NDK includes a set of cross-toolchains (compilers, linkers, etc..) that can generate
    -  native ARM binaries on Linux, OS X, and Windows (with Cygwin) platforms.</p>
    -
    -  <p>It provides a set of system headers for stable native APIs that are guaranteed to be supported
    -  in all later releases of the platform:</p>
    -
    -  <ul>
    -    <li>libc (C library) headers</li>
    -
    -    <li>libm (math library) headers</li>
    -
    -    <li>JNI interface headers</li>
    -
    -    <li>libz (Zlib compression) headers</li>
    -
    -    <li>liblog (Android logging) header</li>
    -
    -    <li>OpenGL ES 1.1 and OpenGL ES 2.0 (3D graphics libraries) headers</li>
    -
    -    <li>libjnigraphics (Pixel buffer access) header (for Android 2.2 and above).</li>
    -
    -    <li>A Minimal set of headers for C++ support</li>
    -    
    -    <li>OpenSL ES native audio libraries</li>
    -    
    -    <li>Android native application APIS</li>
    -  </ul>
    -
    -  <p>The NDK also provides a build system that lets you work efficiently with your sources, without
    -  having to handle the toolchain/platform/CPU/ABI details. You create very short build files to
    -  describe which sources to compile and which Android application will use them &mdash; the build
    -  system compiles the sources and places the shared libraries directly in your application
    -  project.</p>
    -
    -  <p class="caution"><strong>Important:</strong> With the exception of the libraries listed above,
    -  native system libraries in the Android platform are <em>not</em> stable and may change in future
    -  platform versions. Your applications should <em>only</em> make use of the stable native system
    -  libraries provided in this NDK.</p>
    -
    -  <h3 id="docs">Documentation</h3>
    -
    -  <p>The NDK package includes a set of documentation that describes the capabilities of the NDK and
    -  how to use it to create shared libraries for your Android applications. In this release, the
    -  documentation is provided only in the downloadable NDK package. You can find the documentation in
    -  the <code>&lt;ndk&gt;/docs/</code> directory. Included are these files (partial listing):</p>
    -
    -  <ul>
    -    <li>
    -    INSTALL.HTML &mdash; describes how to install the NDK and configure it for your host
    -    system</li>
    -
    -    <li>OVERVIEW.HTML &mdash; provides an overview of the NDK capabilities and usage</li>
    -    
    -    <li>ANDROID-MK.HTML &mdash; describes the use of the Android.mk file, which defines the native
    -    sources you want to compile</li>
    -    
    -    <li>APPLICATION-MK.HTML &mdash; describes the use of the Application.mk file, which describes
    -    the native sources required by your Android application</li>    
    -    <li>CPLUSPLUS-SUPPORT.HTML &mdash; describes the C++ support provided in the Android NDK</li>    
    -    <li>CPU-ARCH-ABIS.HTML &mdash; a description of supported CPU architectures and how to target
    -    them.</li>
    -
    -    <li>CPU-FEATURES.HTML &mdash; a description of the <code>cpufeatures</code> static library that
    -    lets your application code detect the target device's CPU family and the optional features at
    -    runtime.</li>
    -
    -    <li>CHANGES.HTML &mdash; a complete list of changes to the NDK across all releases.</li>
    -
    -    <li>DEVELOPMENT.HTML &mdash; describes how to modify the NDK and generate release packages for it</li>
    -    
    -    <li>HOWTO.HTML &mdash; information about common tasks associated with NDK development</li>
    -    
    -    <li>IMPORT-MODULE.HTML &mdash; describes how to share and reuse modules</li>
    -    
    -    <li>LICENSES.HTML  &mdash; information about the various open source licenses that govern the Android NDK</li>
    - 
    -    <li>NATIVE-ACTIVITY.HTML &mdash; describes how to implement native activities</li>
    -    
    -    <li>NDK-BUILD.HTML &mdash; describes the usage of the ndk-build script</li>
    -
    -    <li>NDK-GDB.HTML &mdash; describes how to use the native code debugger</li>
    -
    -    <li>PREBUILTS.HTML &mdash; information about how shared and static prebuilt libraries work </li>
    -
    -    <li>STANDALONE-TOOLCHAIN.HTML &mdash; describes how to use Android NDK toolchain as a standalone
    -    compiler (still in beta).</li>
    -    
    -    <li>SYSTEM-ISSUES.HTML &mdash; known issues in the Android system images that you should be
    -    aware of, if you are developing using the NDK.</li>
    -
    -    <li>STABLE-APIS.HTML &mdash; a complete list of the stable APIs exposed by headers in the
    -    NDK.</li>
    -    
    -  </ul>
    -
    -  <p>Additionally, the package includes detailed information about the "bionic" C library provided
    -  with the Android platform that you should be aware of, if you are developing using the NDK. You
    -  can find the documentation in the <code>&lt;ndk&gt;/docs/system/libc/</code> directory:</p>
    -
    -  <ul>
    -    <li>OVERVIEW.HTML &mdash; provides an overview of the "bionic" C library and the features it
    -    offers.</li>
    -  </ul>
    -
    -  <h3 id="samples">Sample applications</h3>
    -
    -<p>The NDK includes sample applications that illustrate how to use native code in your Android
    -  applications:</p>
    -
    -  <ul>
    -    <li><code>hello-jni</code> &mdash; a simple application that loads a string from a native
    -    method implemented in a shared library and then displays it in the application UI.</li>
    -
    -    <li><code>two-libs</code> &mdash; a simple application that loads a shared library dynamically
    -    and calls a native method provided by the library. In this case, the method is implemented in a
    -    static library imported by the shared library.</li>
    -
    -    <li><code>san-angeles</code> &mdash; a simple application that renders 3D graphics through the
    -    native OpenGL ES APIs, while managing activity lifecycle with a {@link
    -    android.opengl.GLSurfaceView} object.</li>
    -
    -    <li><code>hello-gl2</code> &mdash; a simple application that renders a triangle using OpenGL ES
    -    2.0 vertex and fragment shaders.</li>
    -
    -    <li><code>hello-neon</code> &mdash; a simple application that shows how to use the
    -    <code>cpufeatures</code> library to check CPU capabilities at runtime, then use NEON intrinsics
    -    if supported by the CPU. Specifically, the application implements two versions of a tiny
    -    benchmark for a FIR filter loop, a C version and a NEON-optimized version for devices that
    -    support it.</li>
    -
    -    <li><code>bitmap-plasma</code> &mdash; a simple application that demonstrates how to access the
    -    pixel buffers of Android {@link android.graphics.Bitmap} objects from native code, and uses
    -    this to generate an old-school "plasma" effect.</li>
    -
    -    <li><code>native-activity</code> &mdash; a simple application that demonstrates how to use the
    -    native-app-glue static library to create a native activity</li>
    -
    -    <li><code>native-plasma</code> &mdash; a version of bitmap-plasma implemented with a native
    -    activity.</li>
    -  </ul>
    -
    -  <p>For each sample, the NDK includes the corresponding C source code and the necessary Android.mk
    -  and Application.mk files. There are located under <code>&lt;ndk&gt;/samples/&lt;name&gt;/</code>
    -  and their source code can be found under <code>&lt;ndk&gt;/samples/&lt;name&gt;/jni/</code>.</p>
    -
    -  <p>You can build the shared libraries for the sample apps by going into
    -  <code>&lt;ndk&gt;/samples/&lt;name&gt;/</code> then calling the <code>ndk-build</code> command.
    -  The generated shared libraries will be located under
    -  <code>&lt;ndk&gt;/samples/&lt;name&gt;/libs/armeabi/</code> for (ARMv5TE machine code) and/or
    -  <code>&lt;ndk&gt;/samples/&lt;name&gt;/libs/armeabi-v7a/</code> for (ARMv7 machine code).</p>
    -
    -  <p>Next, build the sample Android applications that use the shared libraries:</p>
    -
    -  <ul>
    -    <li>If you are developing in Eclipse with ADT, use the New Project Wizard to create a new
    -    Android project for each sample, using the "Import from Existing Source" option and importing
    -    the source from <code>&lt;ndk&gt;/samples/&lt;name&gt;/</code>. Then, set up an AVD,
    -    if necessary, and build/run the application in the emulator.</li>
    -
    -    <li>If you are developing with Ant, use the <code>android</code> tool to create the build file
    -    for each of the sample projects at <code>&lt;ndk&gt;/samples/&lt;name&gt;/</code>.
    -    Then set up an AVD, if necessary, build your project in the usual way, and run it in the
    -    emulator.</li>    
    -    
    -  </ul>
    -  
    -  <p>For more information about developing with the Android SDK tools and what
    -  you need to do to create, build, and run your applications, see
    -  the <a href="{@docRoot}tools/workflow/index.html">Overview</a>
    -  section for developing on Android.</p>
    -
    -  <h4 id="hello-jni">Exploring the hello-jni Sample</h4>
    -
    -  <p>The hello-jni sample is a simple demonstration on how to use JNI from an Android application.
    -  The HelloJni activity receives a string from a simple C function and displays it in a
    -  TextView.</p>
    -
    -  <p>The main components of the sample include:</p>
    -
    -  <ul>
    -    <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
    -    file, a <code>src/</code> and <code>res</code> directories, and a main activity)</li>
    -
    -    <li>A <code>jni/</code> directory that includes the implemented source file for the native code
    -    as well as the Android.mk file</li>
    -
    -    <li>A <code>tests/</code> directory that contains unit test code.</li>
    -  </ul>
    -
    -  <ol>
    -    <li>Create a new project in Eclipse from the existing sample source or use the
    -    <code>android</code> tool to update the project so it generates a build.xml file that you can
    -    use to build the sample.
    -
    -      <ul>
    -        <li>In Eclipse:
    -
    -          <ol type="a">
    -            <li>Click <strong>File &gt; New Android Project...</strong></li>
    -
    -            <li>Select the <strong>Create project from existing source</strong> radio button.</li>
    -
    -            <li>Select any API level above Android 1.5.</li>
    -
    -            <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
    -            the <code>&lt;ndk-root&gt;/samples/hello-jni</code> directory.</li>
    -
    -            <li>Click <strong>Finish</strong>.</li>
    -          </ol>
    -        </li>
    -
    -        <li>On the command line:
    -
    -          <ol type="a">
    -            <li>Change to the <code>&lt;ndk-root&gt;/samples/hello-jni</code> directory.</li>
    -
    -            <li>Run the following command to generate a build.xml file:
    -              <pre class="no-pretty-print">android update project -p . -s</pre>
    -            </li>
    -          </ol>
    -        </li>
    -      </ul>
    -    </li>
    -
    -    <li>Compile the native code using the <code>ndk-build</code> command.
    -      <pre class="no-pretty-print">
    -cd &lt;ndk-root&gt;/samples/hello-jni
    -&lt;ndk_root&gt;/ndk-build
    -</pre>
    -    </li>
    -
    -    <li>Build and install the application as you would a normal Android application. If you are
    -    using Eclipse, run the application to build and install it on a device. If you are using Ant,
    -    run the following commands from the project directory:
    -      <pre class="no-pretty-print">
    -ant debug
    -adb install bin/HelloJni-debug.apk
    -</pre>
    -    </li>
    -  </ol>
    -
    -  <p>When you run the application on the device, the string <code>Hello JNI</code> should appear on
    -  your device. You can explore the rest of the samples that are located in the
    -  <code>&lt;ndk-root&gt;/samples</code> directory for more examples on how to use the JNI.</p>
    -
    -  <h4 id="native-activity">Exploring the native-activity Sample Application</h4>
    -
    -  <p>The native-activity sample provided with the Android NDK demonstrates how to use the
    -  android_native_app_glue static library. This static library makes creating a native activity
    -  easier by providing you with an implementation that handles your callbacks in another thread, so
    -  you do not have to worry about them blocking your main UI thread. The main parts of the sample
    -  are described below:</p>
    -
    -  <ul>
    -    <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
    -    file, a <code>src/</code> and <code>res</code> directories). The AndroidManifest.xml declares
    -    that the application is native and specifies the .so file of the native activity. See {@link
    -    android.app.NativeActivity} for the source or see the
    -    <code>&lt;ndk_root&gt;/platforms/samples/native-activity/AndroidManifest.xml</code> file.</li>
    -
    -    <li>A <code>jni/</code> directory contains the native activity, main.c, which uses the
    -    <code>android_native_app_glue.h</code> interface to implement the activity. The Android.mk that
    -    describes the native module to the build system also exists here.</li>
    -  </ul>
    -
    -  <p>To build this sample application:</p>
    -
    -  <ol>
    -    <li>Create a new project in Eclipse from the existing sample source or use the
    -    <code>android</code> tool to update the project so it generates a build.xml file that you can
    -    use to build the sample.
    -
    -      <ul>
    -        <li>In Eclipse:
    -
    -          <ol type="a">
    -            <li>Click <strong>File &gt; New Android Project...</strong></li>
    -
    -            <li>Select the <strong>Create project from existing source</strong> radio button.</li>
    -
    -            <li>Select any API level above Android 2.3.</li>
    -
    -            <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
    -            the <code>&lt;ndk-root&gt;/samples/native-activity</code> directory.</li>
    -
    -            <li>Click <strong>Finish</strong>.</li>
    -          </ol>
    -        </li>
    -
    -        <li>On the command line:
    -
    -          <ol type="a">
    -            <li>Change to the <code>&lt;ndk-root&gt;/samples/native-activity</code> directory.</li>
    -
    -            <li>Run the following command to generate a build.xml file:
    -              <pre class="no-pretty-print">
    -android update project -p . -s
    -</pre>
    -            </li>
    -          </ol>
    -        </li>
    -      </ul>
    -    </li>
    -
    -    <li>Compile the native code using the <code>ndk-build</code> command.
    -      <pre class="no-pretty-print">
    -cd &lt;ndk-root&gt;/platforms/samples/android-9/samples/native-activity
    -&lt;ndk_root&gt;/ndk-build
    -</pre>
    -    </li>
    -
    -    <li>Build and install the application as you would a normal Android application. If you are
    -    using Eclipse, run the application to build and install it on a device. If you are using Ant,
    -    run the following commands in the project directory, then run the application on the device:
    -      <pre class="no-pretty-print">
    -ant debug
    -adb install bin/NativeActivity-debug.apk
    -</pre>
    -    </li>
    -  </ol>
    -
    -
    -  <h2 id="reqs">System and Software Requirements</h2>
    -
    -  <p>The sections below describe the system and software requirements for using the Android NDK, as
    -  well as platform compatibility considerations that affect appplications using libraries produced
    -  with the NDK.</p>
    -
    -  <h4>The Android SDK</h4>
    -
    -  <ul>
    -    <li>A complete Android SDK installation (including all dependencies) is required.</li>
    -
    -    <li>Android 1.5 SDK or later version is required.</li>
    -  </ul>
    -
    -  <h4>Supported operating systems</h4>
    -
    -  <ul>
    -    <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
    -
    -    <li>Mac OS X 10.4.8 or later (x86 only)</li>
    -
    -    <li>Linux (32 or 64-bit; Ubuntu 8.04, or other Linux distributions using GLibc 2.7 or
    -later)</li>
    -  </ul>
    -
    -  <h4>Required development tools</h4>
    -
    -  <ul>
    -    <li>For all development platforms, GNU Make 3.81 or later is required. Earlier versions of GNU
    -    Make might work but have not been tested.</li>
    -
    -    <li>A recent version of awk (either GNU Awk or Nawk) is also required.</li>
    -
    -    <li>For Windows, <a href="http://www.cygwin.com">Cygwin</a> 1.7 or higher is required. The NDK
    -    will <em>not</em> work with Cygwin 1.5 installations.</li>
    -  </ul>
    -
    -  <h4 id="platform-compat">Android platform compatibility</h4>
    -
    -  <ul>
    -    <li>The native libraries created by the Android NDK can only be used on devices running
    -      specific minimum Android platform versions. The minimum required platform version depends on
    -      the CPU architecture of the devices you are targeting. The following table details which
    -      Android platform versions are compatible with native code developed for specific CPU
    -      architectures.
    -
    -    <table style="margin:1em;">
    -      <tr>
    -        <th>Native Code CPU Architecture Used</th>
    -        <th>Compatible Android Platform(s)</th>
    -      </tr>
    -
    -      <tr>
    -        <td>ARM, ARM-NEON</td>
    -        <td>Android 1.5 (API Level 3) and higher</td>
    -      </tr>
    -
    -      <tr>
    -        <td>x86</td>
    -        <td>Android 2.3 (API Level 9) and higher</td>
    -      </tr>
    -
    -      <tr>
    -        <td>MIPS</td>
    -        <td>Android 2.3 (API Level 9) and higher</td>
    -      </tr>
    -    </table>
    -
    -      <p>These requirements mean you can use native libraries produced with the NDK in
    -      applications that are deployable to ARM-based devices running Android 1.5 or later. If you are
    -      deploying native libraries to x86 and MIPS-based devices, your application must target Android
    -      2.3 or later.</p>
    -    </li>
    -
    -    <li>To ensure compatibility, an application using a native library produced with the NDK
    -    <em>must</em> declare a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>
    -      &lt;uses-sdk&gt;</code></a> element in its manifest file, with an
    -      <code>android:minSdkVersion</code> attribute value of "3" or higher. For example:
    -
    -<pre style="margin:1em;">
    -&lt;manifest&gt;
    -  &lt;uses-sdk android:minSdkVersion="3" /&gt;
    -  ...
    -&lt;/manifest&gt;
    -</pre>
    -    </li>
    -
    -    <li>If you use this NDK to create a native library that uses the OpenGL ES APIs, the
    -    application containing the library can be deployed only to devices running the minimum platform
    -    versions described in the table below. To ensure compatibility, make sure that your application
    -    declares the proper <code>android:minSdkVersion</code> attribute value, as shown in the
    -    following table.</li>
    -
    -    <li style="list-style: none; display: inline">
    -      <table style="margin:1em;">
    -        <tr>
    -          <th>OpenGL ES Version Used</th>
    -
    -          <th>Compatible Android Platform(s)</th>
    -
    -          <th>Required uses-sdk Attribute</th>
    -        </tr>
    -
    -        <tr>
    -          <td>OpenGL ES 1.1</td>
    -
    -          <td>Android 1.6 (API Level 4) and higher</td>
    -
    -          <td><code>android:minSdkVersion="4"</code></td>
    -        </tr>
    -
    -        <tr>
    -          <td>OpenGL ES 2.0</td>
    -
    -          <td>Android 2.0 (API Level 5) and higher</td>
    -
    -          <td><code>android:minSdkVersion="5"</code></td>
    -        </tr>
    -      </table>
    -
    -      <p>For more information about API Level and its relationship to Android platform versions,
    -      see <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API Levels</a>.</p>
    -    </li>
    -
    -    <li>Additionally, an application using the OpenGL ES APIs should declare a
    -    <code>&lt;uses-feature&gt;</code> element in its manifest, with an
    -    <code>android:glEsVersion</code> attribute that specifies the minimum OpenGl ES version
    -    required by the application. This ensures that Google Play will show your application only
    -    to users whose devices are capable of supporting your application. For example:
    -      <pre style="margin:1em;">
    -&lt;manifest&gt;
    -<!-- Declare that the application uses the OpenGL ES 2.0 API and is designed
    -     to run only on devices that support OpenGL ES 2.0 or higher. -->
    -  &lt;uses-feature android:glEsVersion="0x00020000" /&gt;
    -  ...
    -&lt;/manifest&gt;
    -</pre>
    -
    -      <p>For more information, see the <a href=
    -      "{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
    -      documentation.</p>
    -    </li>
    -
    -    <li>If you use this NDK to create a native library that uses the API to access Android {@link
    -    android.graphics.Bitmap} pixel buffers or utilizes native activities, the application
    -    containing the library can be deployed only to devices running Android 2.2 (API level 8) or
    -    higher. To ensure compatibility, make sure that your application declares <code>&lt;uses-sdk
    -    android:minSdkVersion="8" /&gt;</code> attribute value in its manifest.</li>
    -  </ul>
    
    diff --git a/docs/html/tools/sdk/older_releases.jd b/docs/html/tools/sdk/older_releases.jd
    index bb274b6..94baa92 100644
    --- a/docs/html/tools/sdk/older_releases.jd
    +++ b/docs/html/tools/sdk/older_releases.jd
    
    @@ -1,4 +1,5 @@
     page.title=SDK Archives
    +excludeFromSuggestions=true
     @jd:body
     
     <p>This page provides a full list of archived and obsolete SDK releases,
    
    diff --git a/docs/html/tools/sdk/platforms.jd b/docs/html/tools/sdk/platforms.jd
    deleted file mode 100644
    index 27e89de..0000000
    --- a/docs/html/tools/sdk/platforms.jd
    +++ /dev/null
    
    @@ -1,9 +0,0 @@
    -page.title=Android Development Platforms
    -
    -@jd:body
    -
    -
    -
    -<p>A page that lists platforms and links to release notes. Links to dashboards etc.</p>
    -
    -
    
    diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
    index 7d121844..4d8aa34 100644
    --- a/docs/html/tools/sdk/tools-notes.jd
    +++ b/docs/html/tools/sdk/tools-notes.jd
    
    @@ -1,4 +1,5 @@
     page.title=SDK Tools
    +excludeFromSuggestions=true
     @jd:body
     
     <p>SDK Tools is a downloadable component for the Android SDK. It includes the
    
    diff --git a/docs/html/tools/sdk/usb-drivers.jd b/docs/html/tools/sdk/usb-drivers.jd
    deleted file mode 100644
    index 27e89de..0000000
    --- a/docs/html/tools/sdk/usb-drivers.jd
    +++ /dev/null
    
    @@ -1,9 +0,0 @@
    -page.title=Android Development Platforms
    -
    -@jd:body
    -
    -
    -
    -<p>A page that lists platforms and links to release notes. Links to dashboards etc.</p>
    -
    -
    
    diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
    index c90f400..d5183d5 100644
    --- a/graphics/java/android/graphics/drawable/Drawable.java
    +++ b/graphics/java/android/graphics/drawable/Drawable.java
    
    @@ -17,6 +17,7 @@
     package android.graphics.drawable;
     
     import android.graphics.Insets;
    +import android.os.Trace;
     import org.xmlpull.v1.XmlPullParser;
     import org.xmlpull.v1.XmlPullParserException;
     
    @@ -745,7 +746,12 @@
          * Create a drawable from an inputstream
          */
         public static Drawable createFromStream(InputStream is, String srcName) {
    -        return createFromResourceStream(null, null, is, srcName, null);
    +        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
    +        try {
    +            return createFromResourceStream(null, null, is, srcName, null);
    +        } finally {
    +            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
    +        }
         }
     
         /**
    @@ -754,7 +760,12 @@
          */
         public static Drawable createFromResourceStream(Resources res, TypedValue value,
                 InputStream is, String srcName) {
    -        return createFromResourceStream(res, value, is, srcName, null);
    +        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
    +        try {
    +            return createFromResourceStream(res, value, is, srcName, null);
    +        } finally {
    +            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
    +        }
         }
     
         /**
    @@ -900,9 +911,14 @@
                 return null;
             }
     
    -        Bitmap bm = BitmapFactory.decodeFile(pathName);
    -        if (bm != null) {
    -            return drawableFromBitmap(null, bm, null, null, null, pathName);
    +        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
    +        try {
    +            Bitmap bm = BitmapFactory.decodeFile(pathName);
    +            if (bm != null) {
    +                return drawableFromBitmap(null, bm, null, null, null, pathName);
    +            }
    +        } finally {
    +            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
             }
     
             return null;
    
    diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
    index acc6b99..5d1990a 100644
    --- a/graphics/java/android/renderscript/Allocation.java
    +++ b/graphics/java/android/renderscript/Allocation.java
    
    @@ -278,20 +278,12 @@
                 }
             }
     
    -        // don't need to account for USAGE_SHARED Allocations
    -        if ((usage & USAGE_SHARED) == 0) {
    -            int numBytes = t.getCount() * t.getElement().getBytesSize();
    -            rs.addAllocSizeForGC(numBytes);
    -            mGCSize = numBytes;
    -        }
    -
             mType = t;
             mUsage = usage;
     
             if (t != null) {
                 updateCacheInfo(t);
             }
    -
         }
     
         private void validateIsInt32() {
    @@ -1258,7 +1250,6 @@
             if (type.getID(rs) == 0) {
                 throw new RSInvalidStateException("Bad Type");
             }
    -
             int id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
             if (id == 0) {
                 throw new RSRuntimeException("Allocation creation failed.");
    @@ -1408,6 +1399,7 @@
                 return alloc;
             }
     
    +
             int id = rs.nAllocationCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
             if (id == 0) {
                 throw new RSRuntimeException("Load failed.");
    
    diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
    index c2ebc9f..f464f9b 100644
    --- a/graphics/java/android/renderscript/BaseObj.java
    +++ b/graphics/java/android/renderscript/BaseObj.java
    
    @@ -71,9 +71,6 @@
         private int mID;
         private boolean mDestroyed;
         private String mName;
    -
    -    int mGCSize;
    -
         RenderScript mRS;
     
         /**
    @@ -138,9 +135,6 @@
                 throw new RSInvalidStateException("Object already destroyed.");
             }
             mDestroyed = true;
    -        if (mGCSize != 0) {
    -            mRS.removeAllocSizeForGC(mGCSize);
    -        }
             mRS.nObjDestroy(mID);
         }
     
    
    diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java
    index 0a7e882..decd0c7 100644
    --- a/graphics/java/android/renderscript/FieldPacker.java
    +++ b/graphics/java/android/renderscript/FieldPacker.java
    
    @@ -16,6 +16,8 @@
     
     package android.renderscript;
     
    +import android.util.Log;
    +import java.util.BitSet;
     
     /**
      * Utility class for packing arguments and structures from Android system objects to
    @@ -27,12 +29,14 @@
             mPos = 0;
             mLen = len;
             mData = new byte[len];
    +        mAlignment = new BitSet();
         }
     
         public FieldPacker(byte[] data) {
             mPos = 0;
             mLen = data.length;
             mData = data;
    +        mAlignment = new BitSet();
         }
     
         public void align(int v) {
    @@ -41,10 +45,29 @@
             }
     
             while ((mPos & (v - 1)) != 0) {
    +            mAlignment.flip(mPos);
                 mData[mPos++] = 0;
             }
         }
     
    +    public void subalign(int v) {
    +        if ((v & (v - 1)) != 0) {
    +            throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
    +        }
    +
    +        while ((mPos & (v - 1)) != 0) {
    +            mPos--;
    +        }
    +
    +        if (mPos > 0) {
    +            while (mAlignment.get(mPos - 1) == true) {
    +                mPos--;
    +                mAlignment.flip(mPos);
    +            }
    +        }
    +
    +    }
    +
         public void reset() {
             mPos = 0;
         }
    @@ -67,12 +90,26 @@
             mData[mPos++] = v;
         }
     
    +    public byte subI8() {
    +        subalign(1);
    +        return mData[--mPos];
    +    }
    +
         public void addI16(short v) {
             align(2);
             mData[mPos++] = (byte)(v & 0xff);
             mData[mPos++] = (byte)(v >> 8);
         }
     
    +    public short subI16() {
    +        subalign(2);
    +        short v = 0;
    +        v = (short)((mData[--mPos] & 0xff) << 8);
    +        v = (short)(v | (short)(mData[--mPos] & 0xff));
    +        return v;
    +    }
    +
    +
         public void addI32(int v) {
             align(4);
             mData[mPos++] = (byte)(v & 0xff);
    @@ -81,6 +118,17 @@
             mData[mPos++] = (byte)((v >> 24) & 0xff);
         }
     
    +    public int subI32() {
    +        subalign(4);
    +        int v = 0;
    +        v = ((mData[--mPos] & 0xff) << 24);
    +        v = v | ((mData[--mPos] & 0xff) << 16);
    +        v = v | ((mData[--mPos] & 0xff) << 8);
    +        v = v | ((mData[--mPos] & 0xff));
    +        return v;
    +    }
    +
    +
         public void addI64(long v) {
             align(8);
             mData[mPos++] = (byte)(v & 0xff);
    @@ -93,6 +141,29 @@
             mData[mPos++] = (byte)((v >> 56) & 0xff);
         }
     
    +    public long subI64() {
    +        subalign(8);
    +        long v = 0;
    +        byte x = 0;
    +        x = ((mData[--mPos]));
    +        v = (long)(v | (((long)x) & 0xff) << 56l);
    +        x = ((mData[--mPos]));
    +        v = (long)(v | (((long)x) & 0xff) << 48l);
    +        x = ((mData[--mPos]));
    +        v = (long)(v | (((long)x) & 0xff) << 40l);
    +        x = ((mData[--mPos]));
    +        v = (long)(v | (((long)x) & 0xff) << 32l);
    +        x = ((mData[--mPos]));
    +        v = (long)(v | (((long)x) & 0xff) << 24l);
    +        x = ((mData[--mPos]));
    +        v = (long)(v | (((long)x) & 0xff) << 16l);
    +        x = ((mData[--mPos]));
    +        v = (long)(v | (((long)x) & 0xff) << 8l);
    +        x = ((mData[--mPos]));
    +        v = (long)(v | (((long)x) & 0xff));
    +        return v;
    +    }
    +
         public void addU8(short v) {
             if ((v < 0) || (v > 0xff)) {
                 android.util.Log.e("rs", "FieldPacker.addU8( " + v + " )");
    @@ -143,10 +214,18 @@
             addI32(Float.floatToRawIntBits(v));
         }
     
    +    public float subF32() {
    +        return Float.intBitsToFloat(subI32());
    +    }
    +
         public void addF64(double v) {
             addI64(Double.doubleToRawLongBits(v));
         }
     
    +    public double subF64() {
    +        return Double.longBitsToDouble(subI64());
    +    }
    +
         public void addObj(BaseObj obj) {
             if (obj != null) {
                 addI32(obj.getID(null));
    @@ -315,28 +394,195 @@
             addU64(v.w);
         }
     
    +
    +    public Float2 subFloat2() {
    +        Float2 v = new Float2();
    +        v.y = subF32();
    +        v.x = subF32();
    +        return v;
    +    }
    +    public Float3 subFloat3() {
    +        Float3 v = new Float3();
    +        v.z = subF32();
    +        v.y = subF32();
    +        v.x = subF32();
    +        return v;
    +    }
    +    public Float4 subFloat4() {
    +        Float4 v = new Float4();
    +        v.w = subF32();
    +        v.z = subF32();
    +        v.y = subF32();
    +        v.x = subF32();
    +        return v;
    +    }
    +
    +    public Double2 subDouble2() {
    +        Double2 v = new Double2();
    +        v.y = subF64();
    +        v.x = subF64();
    +        return v;
    +    }
    +    public Double3 subDouble3() {
    +        Double3 v = new Double3();
    +        v.z = subF64();
    +        v.y = subF64();
    +        v.x = subF64();
    +        return v;
    +    }
    +    public Double4 subDouble4() {
    +        Double4 v = new Double4();
    +        v.w = subF64();
    +        v.z = subF64();
    +        v.y = subF64();
    +        v.x = subF64();
    +        return v;
    +    }
    +
    +    public Byte2 subByte2() {
    +        Byte2 v = new Byte2();
    +        v.y = subI8();
    +        v.x = subI8();
    +        return v;
    +    }
    +    public Byte3 subByte3() {
    +        Byte3 v = new Byte3();
    +        v.z = subI8();
    +        v.y = subI8();
    +        v.x = subI8();
    +        return v;
    +    }
    +    public Byte4 subByte4() {
    +        Byte4 v = new Byte4();
    +        v.w = subI8();
    +        v.z = subI8();
    +        v.y = subI8();
    +        v.x = subI8();
    +        return v;
    +    }
    +
    +    public Short2 subShort2() {
    +        Short2 v = new Short2();
    +        v.y = subI16();
    +        v.x = subI16();
    +        return v;
    +    }
    +    public Short3 subShort3() {
    +        Short3 v = new Short3();
    +        v.z = subI16();
    +        v.y = subI16();
    +        v.x = subI16();
    +        return v;
    +    }
    +    public Short4 subShort4() {
    +        Short4 v = new Short4();
    +        v.w = subI16();
    +        v.z = subI16();
    +        v.y = subI16();
    +        v.x = subI16();
    +        return v;
    +    }
    +
    +    public Int2 subInt2() {
    +        Int2 v = new Int2();
    +        v.y = subI32();
    +        v.x = subI32();
    +        return v;
    +    }
    +    public Int3 subInt3() {
    +        Int3 v = new Int3();
    +        v.z = subI32();
    +        v.y = subI32();
    +        v.x = subI32();
    +        return v;
    +    }
    +    public Int4 subInt4() {
    +        Int4 v = new Int4();
    +        v.w = subI32();
    +        v.z = subI32();
    +        v.y = subI32();
    +        v.x = subI32();
    +        return v;
    +    }
    +
    +    public Long2 subLong2() {
    +        Long2 v = new Long2();
    +        v.y = subI64();
    +        v.x = subI64();
    +        return v;
    +    }
    +    public Long3 subLong3() {
    +        Long3 v = new Long3();
    +        v.z = subI64();
    +        v.y = subI64();
    +        v.x = subI64();
    +        return v;
    +    }
    +    public Long4 subLong4() {
    +        Long4 v = new Long4();
    +        v.w = subI64();
    +        v.z = subI64();
    +        v.y = subI64();
    +        v.x = subI64();
    +        return v;
    +    }
    +
    +
    +
         public void addMatrix(Matrix4f v) {
             for (int i=0; i < v.mMat.length; i++) {
                 addF32(v.mMat[i]);
             }
         }
     
    +    public Matrix4f subMatrix4f() {
    +        Matrix4f v = new Matrix4f();
    +        for (int i = v.mMat.length - 1; i >= 0; i--) {
    +            v.mMat[i] = subF32();
    +        }
    +        return v;
    +    }
    +
         public void addMatrix(Matrix3f v) {
             for (int i=0; i < v.mMat.length; i++) {
                 addF32(v.mMat[i]);
             }
         }
     
    +    public Matrix3f subMatrix3f() {
    +        Matrix3f v = new Matrix3f();
    +        for (int i = v.mMat.length - 1; i >= 0; i--) {
    +            v.mMat[i] = subF32();
    +        }
    +        return v;
    +    }
    +
         public void addMatrix(Matrix2f v) {
             for (int i=0; i < v.mMat.length; i++) {
                 addF32(v.mMat[i]);
             }
         }
     
    +    public Matrix2f subMatrix2f() {
    +        Matrix2f v = new Matrix2f();
    +        for (int i = v.mMat.length - 1; i >= 0; i--) {
    +            v.mMat[i] = subF32();
    +        }
    +        return v;
    +    }
    +
         public void addBoolean(boolean v) {
             addI8((byte)(v ? 1 : 0));
         }
     
    +    public boolean subBoolean() {
    +        byte v = subI8();
    +        if (v == 1) {
    +            return true;
    +        }
    +        return false;
    +    }
    +
         public final byte[] getData() {
             return mData;
         }
    @@ -344,6 +590,7 @@
         private final byte mData[];
         private int mPos;
         private int mLen;
    +    private BitSet mAlignment;
     
     }
     
    
    diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
    index a49070e..6f614c3 100644
    --- a/graphics/java/android/renderscript/RenderScript.java
    +++ b/graphics/java/android/renderscript/RenderScript.java
    
    @@ -18,9 +18,7 @@
     
     import java.io.File;
     import java.lang.reflect.Field;
    -import java.util.concurrent.locks.*;
     
    -import android.app.ActivityManager;
     import android.content.Context;
     import android.content.pm.ApplicationInfo;
     import android.content.pm.PackageManager;
    @@ -99,9 +97,29 @@
             mCacheDir = cacheDir;
         }
     
    +    /**
    +     * ContextType specifies the specific type of context to be created.
    +     *
    +     */
         public enum ContextType {
    +        /**
    +         * NORMAL context, this is the default and what shipping apps should
    +         * use.
    +         */
             NORMAL (0),
    +
    +        /**
    +         * DEBUG context, perform extra runtime checks to validate the
    +         * kernels and APIs are being used as intended.  Get and SetElementAt
    +         * will be bounds checked in this mode.
    +         */
             DEBUG (1),
    +
    +        /**
    +         * PROFILE context, Intended to be used once the first time an
    +         * application is run on a new device.  This mode allows the runtime to
    +         * do additional testing and performance tuning.
    +         */
             PROFILE (2);
     
             int mID;
    @@ -582,31 +600,59 @@
             validate();
             rsnScriptInvokeV(mContext, id, slot, params);
         }
    +
         native void rsnScriptSetVarI(int con, int id, int slot, int val);
         synchronized void nScriptSetVarI(int id, int slot, int val) {
             validate();
             rsnScriptSetVarI(mContext, id, slot, val);
         }
    +    native int rsnScriptGetVarI(int con, int id, int slot);
    +    synchronized int nScriptGetVarI(int id, int slot) {
    +        validate();
    +        return rsnScriptGetVarI(mContext, id, slot);
    +    }
    +
         native void rsnScriptSetVarJ(int con, int id, int slot, long val);
         synchronized void nScriptSetVarJ(int id, int slot, long val) {
             validate();
             rsnScriptSetVarJ(mContext, id, slot, val);
         }
    +    native long rsnScriptGetVarJ(int con, int id, int slot);
    +    synchronized long nScriptGetVarJ(int id, int slot) {
    +        validate();
    +        return rsnScriptGetVarJ(mContext, id, slot);
    +    }
    +
         native void rsnScriptSetVarF(int con, int id, int slot, float val);
         synchronized void nScriptSetVarF(int id, int slot, float val) {
             validate();
             rsnScriptSetVarF(mContext, id, slot, val);
         }
    +    native float rsnScriptGetVarF(int con, int id, int slot);
    +    synchronized float nScriptGetVarF(int id, int slot) {
    +        validate();
    +        return rsnScriptGetVarF(mContext, id, slot);
    +    }
         native void rsnScriptSetVarD(int con, int id, int slot, double val);
         synchronized void nScriptSetVarD(int id, int slot, double val) {
             validate();
             rsnScriptSetVarD(mContext, id, slot, val);
         }
    +    native double rsnScriptGetVarD(int con, int id, int slot);
    +    synchronized double nScriptGetVarD(int id, int slot) {
    +        validate();
    +        return rsnScriptGetVarD(mContext, id, slot);
    +    }
         native void rsnScriptSetVarV(int con, int id, int slot, byte[] val);
         synchronized void nScriptSetVarV(int id, int slot, byte[] val) {
             validate();
             rsnScriptSetVarV(mContext, id, slot, val);
         }
    +    native void rsnScriptGetVarV(int con, int id, int slot, byte[] val);
    +    synchronized void nScriptGetVarV(int id, int slot, byte[] val) {
    +        validate();
    +        rsnScriptGetVarV(mContext, id, slot, val);
    +    }
         native void rsnScriptSetVarVE(int con, int id, int slot, byte[] val,
                                       int e, int[] dims);
         synchronized void nScriptSetVarVE(int id, int slot, byte[] val,
    @@ -756,8 +802,6 @@
         int     mContext;
         @SuppressWarnings({"FieldCanBeLocal"})
         MessageThread mMessageThread;
    -    GCThread mGCThread;
    -
     
         Element mElement_U8;
         Element mElement_I8;
    @@ -887,7 +931,8 @@
         }
     
         /**
    -     * @hide
    +     * Place a message into the message queue to be sent back to the message
    +     * handler once all previous commands have been executed.
          *
          * @param id
          * @param data
    @@ -1046,60 +1091,6 @@
             }
         }
     
    -    static class GCThread extends Thread {
    -        RenderScript mRS;
    -        boolean mRun = true;
    -
    -        long currentSize = 0;
    -        long targetSize; // call System.gc after 512MB of allocs
    -
    -        final Lock lock = new ReentrantLock();
    -        final Condition cond = lock.newCondition();
    -
    -        GCThread(RenderScript rs) {
    -            super("RSGCThread");
    -            mRS = rs;
    -
    -        }
    -
    -        public void run() {
    -            ActivityManager am = (ActivityManager)mRS.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
    -            ActivityManager.MemoryInfo meminfo = new ActivityManager.MemoryInfo();
    -            am.getMemoryInfo(meminfo);
    -            targetSize = (long)(meminfo.totalMem * .5f);
    -
    -            while(mRun) {
    -                System.gc();
    -                lock.lock();
    -                try {
    -                    cond.awaitUninterruptibly();
    -                } finally {
    -                    lock.unlock();
    -                }
    -            }
    -
    -            Log.d(LOG_TAG, "GCThread exiting.");
    -        }
    -
    -        public synchronized void addAllocSize(long bytes) {
    -            currentSize += bytes;
    -            if (currentSize >= targetSize) {
    -                lock.lock();
    -                try {
    -                    cond.signal();
    -                } finally {
    -                    lock.unlock();
    -                }
    -            }
    -        }
    -
    -        public synchronized void removeAllocSize(long bytes) {
    -            currentSize -= bytes;
    -        }
    -
    -    }
    -
    -
         RenderScript(Context ctx) {
             if (ctx != null) {
                 mApplicationContext = ctx.getApplicationContext();
    @@ -1122,15 +1113,6 @@
             return create(ctx, sdkVersion, ContextType.NORMAL);
         }
     
    -    void addAllocSizeForGC(int bytes) {
    -        mGCThread.addAllocSize(bytes);
    -    }
    -
    -    void removeAllocSizeForGC(int bytes) {
    -        mGCThread.removeAllocSize(bytes);
    -    }
    -
    -
         /**
          * Create a basic RenderScript context.
          *
    @@ -1147,9 +1129,7 @@
                 throw new RSDriverException("Failed to create RS context.");
             }
             rs.mMessageThread = new MessageThread(rs);
    -        rs.mGCThread = new GCThread(rs);
             rs.mMessageThread.start();
    -        rs.mGCThread.start();
             return rs;
         }
     
    @@ -1166,9 +1146,9 @@
         /**
          * Create a basic RenderScript context.
          *
    -     * @hide
          *
          * @param ctx The context.
    +     * @param ct The type of context to be created.
          * @return RenderScript
          */
         public static RenderScript create(Context ctx, ContextType ct) {
    @@ -1204,11 +1184,8 @@
             validate();
             nContextDeinitToClient(mContext);
             mMessageThread.mRun = false;
    -        mGCThread.mRun = false;
    -        mGCThread.addAllocSize(0);
             try {
                 mMessageThread.join();
    -            mGCThread.join();
             } catch(InterruptedException e) {
             }
     
    
    diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java
    index fad8838..52034b1 100644
    --- a/graphics/java/android/renderscript/RenderScriptGL.java
    +++ b/graphics/java/android/renderscript/RenderScriptGL.java
    
    @@ -198,9 +198,6 @@
             }
             mMessageThread = new MessageThread(this);
             mMessageThread.start();
    -        mGCThread = new GCThread(this);
    -        mGCThread.start();
    -
         }
     
         /**
    
    diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
    index b405588..b4ba943 100644
    --- a/graphics/java/android/renderscript/Script.java
    +++ b/graphics/java/android/renderscript/Script.java
    
    @@ -220,6 +220,9 @@
         public void setVar(int index, float v) {
             mRS.nScriptSetVarF(getID(mRS), index, v);
         }
    +    public float getVarF(int index) {
    +        return mRS.nScriptGetVarF(getID(mRS), index);
    +    }
     
         /**
          * Only intended for use by generated reflected code.
    @@ -230,6 +233,9 @@
         public void setVar(int index, double v) {
             mRS.nScriptSetVarD(getID(mRS), index, v);
         }
    +    public double getVarD(int index) {
    +        return mRS.nScriptGetVarD(getID(mRS), index);
    +    }
     
         /**
          * Only intended for use by generated reflected code.
    @@ -240,6 +246,10 @@
         public void setVar(int index, int v) {
             mRS.nScriptSetVarI(getID(mRS), index, v);
         }
    +    public int getVarI(int index) {
    +        return mRS.nScriptGetVarI(getID(mRS), index);
    +    }
    +
     
         /**
          * Only intended for use by generated reflected code.
    @@ -250,6 +260,10 @@
         public void setVar(int index, long v) {
             mRS.nScriptSetVarJ(getID(mRS), index, v);
         }
    +    public long getVarJ(int index) {
    +        return mRS.nScriptGetVarJ(getID(mRS), index);
    +    }
    +
     
         /**
          * Only intended for use by generated reflected code.
    @@ -260,6 +274,9 @@
         public void setVar(int index, boolean v) {
             mRS.nScriptSetVarI(getID(mRS), index, v ? 1 : 0);
         }
    +    public boolean getVarB(int index) {
    +        return mRS.nScriptGetVarI(getID(mRS), index) > 0 ? true : false;
    +    }
     
         /**
          * Only intended for use by generated reflected code.
    @@ -293,6 +310,10 @@
             mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), e.getID(mRS), dims);
         }
     
    +    public void getVarV(int index, FieldPacker v) {
    +        mRS.nScriptGetVarV(getID(mRS), index, v.getData());
    +    }
    +
         public void setTimeZone(String timeZone) {
             mRS.validate();
             try {
    
    diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
    index 2f69775..221f760 100644
    --- a/graphics/java/android/renderscript/ScriptC.java
    +++ b/graphics/java/android/renderscript/ScriptC.java
    
    @@ -60,8 +60,6 @@
                 throw new RSRuntimeException("Loading of ScriptC script failed.");
             }
             setID(id);
    -        mGCSize = 2 * 1024 * 1024;
    -        rs.addAllocSizeForGC(mGCSize);
         }
     
         /**
    
    diff --git a/graphics/java/android/renderscript/ScriptIntrinsic3DLUT.java b/graphics/java/android/renderscript/ScriptIntrinsic3DLUT.java
    index 3e58b87..86f37d8 100644
    --- a/graphics/java/android/renderscript/ScriptIntrinsic3DLUT.java
    +++ b/graphics/java/android/renderscript/ScriptIntrinsic3DLUT.java
    
    @@ -20,7 +20,11 @@
     
     /**
      *
    - * @hide
    + * Intrinsic for converting RGB to RGBA by using a 3D lookup table.  The
    + * incoming r,g,b values are use as normalized x,y,z coordinates into a 3D
    + * allocation.  The 8 nearest values are sampled and linearly interpolated.  The
    + * result is placed in the output.
    + *
      **/
     public final class ScriptIntrinsic3DLUT extends ScriptIntrinsic {
         private Allocation mLUT;
    
    diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
    index d7c8255..a5e24ce 100644
    --- a/graphics/java/android/renderscript/Type.java
    +++ b/graphics/java/android/renderscript/Type.java
    
    @@ -112,7 +112,7 @@
         /**
          * Get the YUV format
          *
    -     * @hide
    +     *
          * @return int
          */
         public int getYuv() {
    @@ -277,7 +277,9 @@
             }
     
             /**
    -         * @hide
    +         * Set the YUV layout for a Type.  This controls how the memory is
    +         * interpreted.  Generally and application should not need to call this
    +         * function and it would be set by the Camera.
              *
              * only NV21, YV12.  Enums from ImageFormat
              */
    
    diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
    index 460a516..b9f8713 100644
    --- a/graphics/jni/android_renderscript_RenderScript.cpp
    +++ b/graphics/jni/android_renderscript_RenderScript.cpp
    
    @@ -987,6 +987,15 @@
         rsScriptSetVarI(con, (RsScript)script, slot, val);
     }
     
    +static jint
    +nScriptGetVarI(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot)
    +{
    +    LOG_API("nScriptGetVarI, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
    +    int value = 0;
    +    rsScriptGetVarV(con, (RsScript)script, slot, &value, sizeof(value));
    +    return value;
    +}
    +
     static void
     nScriptSetVarObj(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jint val)
     {
    @@ -1001,6 +1010,15 @@
         rsScriptSetVarJ(con, (RsScript)script, slot, val);
     }
     
    +static jlong
    +nScriptGetVarJ(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot)
    +{
    +    LOG_API("nScriptGetVarJ, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
    +    jlong value = 0;
    +    rsScriptGetVarV(con, (RsScript)script, slot, &value, sizeof(value));
    +    return value;
    +}
    +
     static void
     nScriptSetVarF(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, float val)
     {
    @@ -1008,6 +1026,15 @@
         rsScriptSetVarF(con, (RsScript)script, slot, val);
     }
     
    +static jfloat
    +nScriptGetVarF(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot)
    +{
    +    LOG_API("nScriptGetVarF, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
    +    jfloat value = 0;
    +    rsScriptGetVarV(con, (RsScript)script, slot, &value, sizeof(value));
    +    return value;
    +}
    +
     static void
     nScriptSetVarD(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, double val)
     {
    @@ -1015,6 +1042,15 @@
         rsScriptSetVarD(con, (RsScript)script, slot, val);
     }
     
    +static jdouble
    +nScriptGetVarD(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot)
    +{
    +    LOG_API("nScriptGetVarD, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
    +    jdouble value = 0;
    +    rsScriptGetVarV(con, (RsScript)script, slot, &value, sizeof(value));
    +    return value;
    +}
    +
     static void
     nScriptSetVarV(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jbyteArray data)
     {
    @@ -1026,6 +1062,16 @@
     }
     
     static void
    +nScriptGetVarV(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jbyteArray data)
    +{
    +    LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
    +    jint len = _env->GetArrayLength(data);
    +    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
    +    rsScriptGetVarV(con, (RsScript)script, slot, ptr, len);
    +    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
    +}
    +
    +static void
     nScriptSetVarVE(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jbyteArray data, jint elem, jintArray dims)
     {
         LOG_API("nScriptSetVarVE, con(%p), s(%p), slot(%i)", con, (void *)script, slot);
    @@ -1600,10 +1646,15 @@
     {"rsnScriptForEachClipped",          "(IIIIIIIIIII)V",                        (void*)nScriptForEachClipped },
     {"rsnScriptForEachClipped",          "(IIIII[BIIIIII)V",                      (void*)nScriptForEachClippedV },
     {"rsnScriptSetVarI",                 "(IIII)V",                               (void*)nScriptSetVarI },
    +{"rsnScriptGetVarI",                 "(III)I",                                (void*)nScriptGetVarI },
     {"rsnScriptSetVarJ",                 "(IIIJ)V",                               (void*)nScriptSetVarJ },
    +{"rsnScriptGetVarJ",                 "(III)J",                                (void*)nScriptGetVarJ },
     {"rsnScriptSetVarF",                 "(IIIF)V",                               (void*)nScriptSetVarF },
    +{"rsnScriptGetVarF",                 "(III)F",                                (void*)nScriptGetVarF },
     {"rsnScriptSetVarD",                 "(IIID)V",                               (void*)nScriptSetVarD },
    +{"rsnScriptGetVarD",                 "(III)D",                                (void*)nScriptGetVarD },
     {"rsnScriptSetVarV",                 "(III[B)V",                              (void*)nScriptSetVarV },
    +{"rsnScriptGetVarV",                 "(III[B)V",                              (void*)nScriptGetVarV },
     {"rsnScriptSetVarVE",                "(III[BI[I)V",                           (void*)nScriptSetVarVE },
     {"rsnScriptSetVarObj",               "(IIII)V",                               (void*)nScriptSetVarObj },
     
    
    diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java
    index c42001b..6975583 100644
    --- a/keystore/java/android/security/AndroidKeyPairGenerator.java
    +++ b/keystore/java/android/security/AndroidKeyPairGenerator.java
    
    @@ -49,10 +49,7 @@
      *
      * {@hide}
      */
    -@SuppressWarnings("deprecation")
     public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
    -    public static final String NAME = "AndroidKeyPairGenerator";
    -
         private android.security.KeyStore mKeyStore;
     
         private AndroidKeyPairGeneratorSpec mSpec;
    @@ -79,12 +76,21 @@
                         "Must call initialize with an AndroidKeyPairGeneratorSpec first");
             }
     
    +        if (((mSpec.getFlags() & KeyStore.FLAG_ENCRYPTED) != 0)
    +                && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
    +            throw new IllegalStateException(
    +                    "Android keystore must be in initialized and unlocked state "
    +                            + "if encryption is required");
    +        }
    +
             final String alias = mSpec.getKeystoreAlias();
     
             Credentials.deleteAllTypesForAlias(mKeyStore, alias);
     
             final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
    -        mKeyStore.generate(privateKeyAlias);
    +        if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, mSpec.getFlags())) {
    +            throw new IllegalStateException("could not generate key in keystore");
    +        }
     
             final PrivateKey privKey;
             final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
    @@ -131,7 +137,8 @@
                 throw new IllegalStateException("Can't get encoding of certificate", e);
             }
     
    -        if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes)) {
    +        if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes, KeyStore.UID_SELF,
    +                mSpec.getFlags())) {
                 Credentials.deleteAllTypesForAlias(mKeyStore, alias);
                 throw new IllegalStateException("Can't store certificate in AndroidKeyStore");
             }
    
    diff --git a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
    index 18225a5..b126f036 100644
    --- a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
    +++ b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
    
    @@ -32,10 +32,9 @@
      * {@code KeyPairGenerator} that works with <a href="{@docRoot}
      * guide/topics/security/keystore.html">Android KeyStore facility</a>. The
      * Android KeyStore facility is accessed through a
    - * {@link java.security.KeyPairGenerator} API using the
    - * {@code AndroidKeyPairGenerator} provider. The {@code context} passed in may
    - * be used to pop up some UI to ask the user to unlock or initialize the Android
    - * keystore facility.
    + * {@link java.security.KeyPairGenerator} API using the {@code AndroidKeyStore}
    + * provider. The {@code context} passed in may be used to pop up some UI to ask
    + * the user to unlock or initialize the Android KeyStore facility.
      * <p>
      * After generation, the {@code keyStoreAlias} is used with the
      * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
    @@ -47,10 +46,10 @@
      * Distinguished Name along with the other parameters specified with the
      * {@link Builder}.
      * <p>
    - * The self-signed certificate may be replaced at a later time by a certificate
    - * signed by a real Certificate Authority.
    + * The self-signed X.509 certificate may be replaced at a later time by a
    + * certificate signed by a real Certificate Authority.
      */
    -public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec {
    +public final class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec {
         private final String mKeystoreAlias;
     
         private final Context mContext;
    @@ -63,6 +62,8 @@
     
         private final Date mEndDate;
     
    +    private final int mFlags;
    +
         /**
          * Parameter specification for the "{@code AndroidKeyPairGenerator}"
          * instance of the {@link java.security.KeyPairGenerator} API. The
    @@ -93,7 +94,8 @@
          * @hide should be built with AndroidKeyPairGeneratorSpecBuilder
          */
         public AndroidKeyPairGeneratorSpec(Context context, String keyStoreAlias,
    -            X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate) {
    +            X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate,
    +            int flags) {
             if (context == null) {
                 throw new IllegalArgumentException("context == null");
             } else if (TextUtils.isEmpty(keyStoreAlias)) {
    @@ -116,48 +118,69 @@
             mSerialNumber = serialNumber;
             mStartDate = startDate;
             mEndDate = endDate;
    +        mFlags = flags;
         }
     
         /**
    -     * @hide
    +     * Returns the alias that will be used in the {@code java.security.KeyStore}
    +     * in conjunction with the {@code AndroidKeyStore}.
          */
    -    String getKeystoreAlias() {
    +    public String getKeystoreAlias() {
             return mKeystoreAlias;
         }
     
         /**
    -     * @hide
    +     * Gets the Android context used for operations with this instance.
          */
    -    Context getContext() {
    +    public Context getContext() {
             return mContext;
         }
     
         /**
    -     * @hide
    +     * Gets the subject distinguished name to be used on the X.509 certificate
    +     * that will be put in the {@link java.security.KeyStore}.
          */
    -    X500Principal getSubjectDN() {
    +    public X500Principal getSubjectDN() {
             return mSubjectDN;
         }
     
         /**
    -     * @hide
    +     * Gets the serial number to be used on the X.509 certificate that will be
    +     * put in the {@link java.security.KeyStore}.
          */
    -    BigInteger getSerialNumber() {
    +    public BigInteger getSerialNumber() {
             return mSerialNumber;
         }
     
         /**
    -     * @hide
    +     * Gets the start date to be used on the X.509 certificate that will be put
    +     * in the {@link java.security.KeyStore}.
          */
    -    Date getStartDate() {
    +    public Date getStartDate() {
             return mStartDate;
         }
     
         /**
    +     * Gets the end date to be used on the X.509 certificate that will be put in
    +     * the {@link java.security.KeyStore}.
    +     */
    +    public Date getEndDate() {
    +        return mEndDate;
    +    }
    +
    +    /**
          * @hide
          */
    -    Date getEndDate() {
    -        return mEndDate;
    +    int getFlags() {
    +        return mFlags;
    +    }
    +
    +    /**
    +     * Returns {@code true} if this parameter will require generated keys to be
    +     * encrypted in the {@link java.security.KeyStore}.
    +     */
    +    public boolean isEncryptionRequired() {
    +        return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
         }
     
         /**
    @@ -175,16 +198,17 @@
          * Calendar end = new Calendar();
          * end.add(1, Calendar.YEAR);
          *
    -     * AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(mContext)
    -     *         .setAlias("myKey")
    -     *         .setSubject(new X500Principal("CN=myKey"))
    -     *         .setSerial(BigInteger.valueOf(1337))
    -     *         .setStartDate(start.getTime())
    -     *         .setEndDate(end.getTime())
    -     *         .build();
    +     * AndroidKeyPairGeneratorSpec spec =
    +     *         new AndroidKeyPairGeneratorSpec.Builder(mContext)
    +     *                 .setAlias(&quot;myKey&quot;)
    +     *                 .setSubject(new X500Principal(&quot;CN=myKey&quot;))
    +     *                 .setSerial(BigInteger.valueOf(1337))
    +     *                 .setStartDate(start.getTime())
    +     *                 .setEndDate(end.getTime())
    +     *                 .build();
          * </pre>
          */
    -    public static class Builder {
    +    public final static class Builder {
             private final Context mContext;
     
             private String mKeystoreAlias;
    @@ -197,6 +221,14 @@
     
             private Date mEndDate;
     
    +        private int mFlags;
    +
    +        /**
    +         * Creates a new instance of the {@code Builder} with the given
    +         * {@code context}. The {@code context} passed in may be used to pop up
    +         * some UI to ask the user to unlock or initialize the Android KeyStore
    +         * facility.
    +         */
             public Builder(Context context) {
                 if (context == null) {
                     throw new NullPointerException("context == null");
    @@ -266,6 +298,17 @@
             }
     
             /**
    +         * Indicates that this key must be encrypted at rest on storage. Note
    +         * that enabling this will require that the user enable a strong lock
    +         * screen (e.g., PIN, password) before creating or using the generated
    +         * key is successful.
    +         */
    +        public Builder setEncryptionRequired() {
    +            mFlags |= KeyStore.FLAG_ENCRYPTED;
    +            return this;
    +        }
    +
    +        /**
              * Builds the instance of the {@code AndroidKeyPairGeneratorSpec}.
              *
              * @throws IllegalArgumentException if a required field is missing
    @@ -273,7 +316,7 @@
              */
             public AndroidKeyPairGeneratorSpec build() {
                 return new AndroidKeyPairGeneratorSpec(mContext, mKeystoreAlias, mSubjectDN,
    -                    mSerialNumber, mStartDate, mEndDate);
    +                    mSerialNumber, mStartDate, mEndDate, mFlags);
             }
         }
     }
    
    diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
    index 8a9826b..dcc9516 100644
    --- a/keystore/java/android/security/AndroidKeyStore.java
    +++ b/keystore/java/android/security/AndroidKeyStore.java
    
    @@ -27,6 +27,10 @@
     import java.io.OutputStream;
     import java.security.InvalidKeyException;
     import java.security.Key;
    +import java.security.KeyStore.Entry;
    +import java.security.KeyStore.PrivateKeyEntry;
    +import java.security.KeyStore.ProtectionParameter;
    +import java.security.KeyStore;
     import java.security.KeyStoreException;
     import java.security.KeyStoreSpi;
     import java.security.NoSuchAlgorithmException;
    @@ -198,14 +202,14 @@
             }
     
             if (key instanceof PrivateKey) {
    -            setPrivateKeyEntry(alias, (PrivateKey) key, chain);
    +            setPrivateKeyEntry(alias, (PrivateKey) key, chain, null);
             } else {
                 throw new KeyStoreException("Only PrivateKeys are supported");
             }
         }
     
    -    private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain)
    -            throws KeyStoreException {
    +    private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain,
    +            AndroidKeyStoreParameter params) throws KeyStoreException {
             byte[] keyBytes = null;
     
             final String pkeyAlias;
    @@ -317,15 +321,20 @@
                 Credentials.deleteCertificateTypesForAlias(mKeyStore, alias);
             }
     
    +        final int flags = (params == null) ? 0 : params.getFlags();
    +
             if (shouldReplacePrivateKey
    -                && !mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes)) {
    +                && !mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes,
    +                        android.security.KeyStore.UID_SELF, flags)) {
                 Credentials.deleteAllTypesForAlias(mKeyStore, alias);
                 throw new KeyStoreException("Couldn't put private key in keystore");
    -        } else if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertBytes)) {
    +        } else if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertBytes,
    +                android.security.KeyStore.UID_SELF, flags)) {
                 Credentials.deleteAllTypesForAlias(mKeyStore, alias);
                 throw new KeyStoreException("Couldn't put certificate #1 in keystore");
             } else if (chainBytes != null
    -                && !mKeyStore.put(Credentials.CA_CERTIFICATE + alias, chainBytes)) {
    +                && !mKeyStore.put(Credentials.CA_CERTIFICATE + alias, chainBytes,
    +                        android.security.KeyStore.UID_SELF, flags)) {
                 Credentials.deleteAllTypesForAlias(mKeyStore, alias);
                 throw new KeyStoreException("Couldn't put certificate chain in keystore");
             }
    @@ -355,7 +364,8 @@
                 throw new KeyStoreException(e);
             }
     
    -        if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded)) {
    +        if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded,
    +                android.security.KeyStore.UID_SELF, android.security.KeyStore.FLAG_NONE)) {
                 throw new KeyStoreException("Couldn't insert certificate; is KeyStore initialized?");
             }
         }
    @@ -517,4 +527,37 @@
             mKeyStore = android.security.KeyStore.getInstance();
         }
     
    +    @Override
    +    public void engineSetEntry(String alias, Entry entry, ProtectionParameter param)
    +            throws KeyStoreException {
    +        if (entry == null) {
    +            throw new KeyStoreException("entry == null");
    +        }
    +
    +        if (engineContainsAlias(alias)) {
    +            engineDeleteEntry(alias);
    +        }
    +
    +        if (entry instanceof KeyStore.TrustedCertificateEntry) {
    +            KeyStore.TrustedCertificateEntry trE = (KeyStore.TrustedCertificateEntry) entry;
    +            engineSetCertificateEntry(alias, trE.getTrustedCertificate());
    +            return;
    +        }
    +
    +        if (param != null && !(param instanceof AndroidKeyStoreParameter)) {
    +            throw new KeyStoreException("protParam should be AndroidKeyStoreParameter; was: "
    +                    + param.getClass().getName());
    +        }
    +
    +        if (entry instanceof PrivateKeyEntry) {
    +            PrivateKeyEntry prE = (PrivateKeyEntry) entry;
    +            setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(),
    +                    (AndroidKeyStoreParameter) param);
    +            return;
    +        }
    +
    +        throw new KeyStoreException(
    +                "Entry must be a PrivateKeyEntry or TrustedCertificateEntry; was " + entry);
    +    }
    +
     }
    
    diff --git a/keystore/java/android/security/AndroidKeyStoreParameter.java b/keystore/java/android/security/AndroidKeyStoreParameter.java
    new file mode 100644
    index 0000000..44f57c4
    --- /dev/null
    +++ b/keystore/java/android/security/AndroidKeyStoreParameter.java
    
    @@ -0,0 +1,123 @@
    +/*
    + * 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.security;
    +
    +import android.content.Context;
    +import android.security.AndroidKeyPairGeneratorSpec.Builder;
    +
    +import java.security.KeyPairGenerator;
    +import java.security.PrivateKey;
    +import java.security.KeyStore.ProtectionParameter;
    +import java.security.cert.Certificate;
    +
    +/**
    + * This provides the optional parameters that can be specified for
    + * {@code KeyStore} entries that work with <a href="{@docRoot}
    + * guide/topics/security/keystore.html">Android KeyStore facility</a>. The
    + * Android KeyStore facility is accessed through a
    + * {@link java.security.KeyStore} API using the {@code AndroidKeyStore}
    + * provider. The {@code context} passed in may be used to pop up some UI to ask
    + * the user to unlock or initialize the Android KeyStore facility.
    + * <p>
    + * Any entries placed in the {@code KeyStore} may be retrieved later. Note that
    + * there is only one logical instance of the {@code KeyStore} per application
    + * UID so apps using the {@code sharedUid} facility will also share a
    + * {@code KeyStore}.
    + * <p>
    + * Keys may be generated using the {@link KeyPairGenerator} facility with a
    + * {@link AndroidKeyPairGeneratorSpec} to specify the entry's {@code alias}. A
    + * self-signed X.509 certificate will be attached to generated entries, but that
    + * may be replaced at a later time by a certificate signed by a real Certificate
    + * Authority.
    + */
    +public final class AndroidKeyStoreParameter implements ProtectionParameter {
    +    private int mFlags;
    +
    +    private AndroidKeyStoreParameter(int flags) {
    +        mFlags = flags;
    +    }
    +
    +    /**
    +     * @hide
    +     */
    +    public int getFlags() {
    +        return mFlags;
    +    }
    +
    +    /**
    +     * Returns {@code true} if this parameter requires entries to be encrypted
    +     * on the disk.
    +     */
    +    public boolean isEncryptionRequired() {
    +        return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
    +    }
    +
    +    /**
    +     * Builder class for {@link AndroidKeyStoreParameter} objects.
    +     * <p>
    +     * This will build protection parameters for use with the <a
    +     * href="{@docRoot} guide/topics/security/keystore.html">Android KeyStore
    +     * facility</a>.
    +     * <p>
    +     * This can be used to require that KeyStore entries be stored encrypted.
    +     * <p>
    +     * Example:
    +     *
    +     * <pre class="prettyprint">
    +     * AndroidKeyStoreParameter params =
    +     *         new AndroidKeyStoreParameter.Builder(mContext).setEncryptionRequired().build();
    +     * </pre>
    +     */
    +    public final static class Builder {
    +        private int mFlags;
    +
    +        /**
    +         * Creates a new instance of the {@code Builder} with the given
    +         * {@code context}. The {@code context} passed in may be used to pop up
    +         * some UI to ask the user to unlock or initialize the Android KeyStore
    +         * facility.
    +         */
    +        public Builder(Context context) {
    +            if (context == null) {
    +                throw new NullPointerException("context == null");
    +            }
    +
    +            // Context is currently not used, but will be in the future.
    +        }
    +
    +        /**
    +         * Indicates that this key must be encrypted at rest on storage. Note
    +         * that enabling this will require that the user enable a strong lock
    +         * screen (e.g., PIN, password) before creating or using the generated
    +         * key is successful.
    +         */
    +        public Builder setEncryptionRequired() {
    +            mFlags |= KeyStore.FLAG_ENCRYPTED;
    +            return this;
    +        }
    +
    +        /**
    +         * Builds the instance of the {@code AndroidKeyPairGeneratorSpec}.
    +         *
    +         * @throws IllegalArgumentException if a required field is missing
    +         * @return built instance of {@code AndroidKeyPairGeneratorSpec}
    +         */
    +        public AndroidKeyStoreParameter build() {
    +            return new AndroidKeyStoreParameter(mFlags);
    +        }
    +    }
    +}
    
    diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
    index 40d7e1a..8ca301e 100644
    --- a/keystore/java/android/security/AndroidKeyStoreProvider.java
    +++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
    
    @@ -33,7 +33,6 @@
             put("KeyStore." + AndroidKeyStore.NAME, AndroidKeyStore.class.getName());
     
             // java.security.KeyPairGenerator
    -        put("KeyPairGenerator." + AndroidKeyPairGenerator.NAME,
    -                AndroidKeyPairGenerator.class.getName());
    +        put("KeyPairGenerator." + AndroidKeyStore.NAME, AndroidKeyPairGenerator.class.getName());
         }
     }
    
    diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
    index 852f0bb..fb5e039 100644
    --- a/keystore/java/android/security/KeyStore.java
    +++ b/keystore/java/android/security/KeyStore.java
    
    @@ -40,6 +40,13 @@
         public static final int UNDEFINED_ACTION = 9;
         public static final int WRONG_PASSWORD = 10;
     
    +    // Used for UID field to indicate the calling UID.
    +    public static final int UID_SELF = -1;
    +
    +    // Flags for "put" "import" and "generate"
    +    public static final int FLAG_NONE = 0;
    +    public static final int FLAG_ENCRYPTED = 1;
    +
         // States
         public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
     
    @@ -87,19 +94,15 @@
             }
         }
     
    -    public boolean put(String key, byte[] value, int uid) {
    +    public boolean put(String key, byte[] value, int uid, int flags) {
             try {
    -            return mBinder.insert(key, value, uid) == NO_ERROR;
    +            return mBinder.insert(key, value, uid, flags) == NO_ERROR;
             } catch (RemoteException e) {
                 Log.w(TAG, "Cannot connect to keystore", e);
                 return false;
             }
         }
     
    -    public boolean put(String key, byte[] value) {
    -        return put(key, value, -1);
    -    }
    -
         public boolean delete(String key, int uid) {
             try {
                 return mBinder.del(key, uid) == NO_ERROR;
    @@ -110,7 +113,7 @@
         }
     
         public boolean delete(String key) {
    -        return delete(key, -1);
    +        return delete(key, UID_SELF);
         }
     
         public boolean contains(String key, int uid) {
    @@ -123,7 +126,7 @@
         }
     
         public boolean contains(String key) {
    -        return contains(key, -1);
    +        return contains(key, UID_SELF);
         }
     
         public String[] saw(String prefix, int uid) {
    @@ -136,7 +139,7 @@
         }
     
         public String[] saw(String prefix) {
    -        return saw(prefix, -1);
    +        return saw(prefix, UID_SELF);
         }
     
         public boolean reset() {
    @@ -185,32 +188,24 @@
             }
         }
     
    -    public boolean generate(String key, int uid) {
    +    public boolean generate(String key, int uid, int flags) {
             try {
    -            return mBinder.generate(key, uid) == NO_ERROR;
    +            return mBinder.generate(key, uid, flags) == NO_ERROR;
             } catch (RemoteException e) {
                 Log.w(TAG, "Cannot connect to keystore", e);
                 return false;
             }
         }
     
    -    public boolean generate(String key) {
    -        return generate(key, -1);
    -    }
    -
    -    public boolean importKey(String keyName, byte[] key, int uid) {
    +    public boolean importKey(String keyName, byte[] key, int uid, int flags) {
             try {
    -            return mBinder.import_key(keyName, key, uid) == NO_ERROR;
    +            return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
             } catch (RemoteException e) {
                 Log.w(TAG, "Cannot connect to keystore", e);
                 return false;
             }
         }
     
    -    public boolean importKey(String keyName, byte[] key) {
    -        return importKey(keyName, key, -1);
    -    }
    -
         public byte[] getPubkey(String key) {
             try {
                 return mBinder.get_pubkey(key);
    @@ -230,7 +225,7 @@
         }
     
         public boolean delKey(String key) {
    -        return delKey(key, -1);
    +        return delKey(key, UID_SELF);
         }
     
         public byte[] sign(String key, byte[] data) {
    
    diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
    index 3d275cd..5d4ab9c 100644
    --- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
    +++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
    
    @@ -39,8 +39,9 @@
         private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
     
         public void testConstructor_Success() throws Exception {
    -        AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec(getContext(),
    -                TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW, NOW_PLUS_10_YEARS);
    +        AndroidKeyPairGeneratorSpec spec =
    +                new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1,
    +                        NOW, NOW_PLUS_10_YEARS, 0);
     
             assertEquals("Context should be the one specified", getContext(), spec.getContext());
     
    @@ -60,6 +61,7 @@
                     .setSerialNumber(SERIAL_1)
                     .setStartDate(NOW)
                     .setEndDate(NOW_PLUS_10_YEARS)
    +                .setEncryptionRequired()
                     .build();
     
             assertEquals("Context should be the one specified", getContext(), spec.getContext());
    @@ -71,12 +73,14 @@
             assertEquals("startDate should be the one specified", NOW, spec.getStartDate());
     
             assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
    +
    +        assertEquals("encryption flag should be on", KeyStore.FLAG_ENCRYPTED, spec.getFlags());
         }
     
         public void testConstructor_NullContext_Failure() throws Exception {
             try {
                 new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
    -                    NOW_PLUS_10_YEARS);
    +                    NOW_PLUS_10_YEARS, 0);
                 fail("Should throw IllegalArgumentException when context is null");
             } catch (IllegalArgumentException success) {
             }
    @@ -85,7 +89,7 @@
         public void testConstructor_NullKeystoreAlias_Failure() throws Exception {
             try {
                 new AndroidKeyPairGeneratorSpec(getContext(), null, TEST_DN_1, SERIAL_1, NOW,
    -                    NOW_PLUS_10_YEARS);
    +                    NOW_PLUS_10_YEARS, 0);
                 fail("Should throw IllegalArgumentException when keystoreAlias is null");
             } catch (IllegalArgumentException success) {
             }
    @@ -94,7 +98,7 @@
         public void testConstructor_NullSubjectDN_Failure() throws Exception {
             try {
                 new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, null, SERIAL_1, NOW,
    -                    NOW_PLUS_10_YEARS);
    +                    NOW_PLUS_10_YEARS, 0);
                 fail("Should throw IllegalArgumentException when subjectDN is null");
             } catch (IllegalArgumentException success) {
             }
    @@ -103,7 +107,7 @@
         public void testConstructor_NullSerial_Failure() throws Exception {
             try {
                 new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, null, NOW,
    -                    NOW_PLUS_10_YEARS);
    +                    NOW_PLUS_10_YEARS, 0);
                 fail("Should throw IllegalArgumentException when startDate is null");
             } catch (IllegalArgumentException success) {
             }
    @@ -112,7 +116,7 @@
         public void testConstructor_NullStartDate_Failure() throws Exception {
             try {
                 new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, null,
    -                    NOW_PLUS_10_YEARS);
    +                    NOW_PLUS_10_YEARS, 0);
                 fail("Should throw IllegalArgumentException when startDate is null");
             } catch (IllegalArgumentException success) {
             }
    @@ -121,7 +125,7 @@
         public void testConstructor_NullEndDate_Failure() throws Exception {
             try {
                 new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
    -                    null);
    +                    null, 0);
                 fail("Should throw IllegalArgumentException when keystoreAlias is null");
             } catch (IllegalArgumentException success) {
             }
    @@ -130,7 +134,7 @@
         public void testConstructor_EndBeforeStart_Failure() throws Exception {
             try {
                 new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1,
    -                    NOW_PLUS_10_YEARS, NOW);
    +                    NOW_PLUS_10_YEARS, NOW, 0);
                 fail("Should throw IllegalArgumentException when end is before start");
             } catch (IllegalArgumentException success) {
             }
    
    diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
    index 69007c4..c5cf514 100644
    --- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
    +++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
    
    @@ -27,6 +27,7 @@
     import java.security.cert.Certificate;
     import java.security.cert.CertificateFactory;
     import java.security.cert.X509Certificate;
    +import java.text.SimpleDateFormat;
     import java.util.Date;
     
     import javax.security.auth.x500.X500Principal;
    @@ -64,22 +65,34 @@
     
             assertFalse(mAndroidKeyStore.isUnlocked());
     
    +        mGenerator = java.security.KeyPairGenerator.getInstance("AndroidKeyStore");
    +    }
    +
    +    private void setupPassword() {
             assertTrue(mAndroidKeyStore.password("1111"));
             assertTrue(mAndroidKeyStore.isUnlocked());
     
             String[] aliases = mAndroidKeyStore.saw("");
             assertNotNull(aliases);
             assertEquals(0, aliases.length);
    -
    -        mGenerator = java.security.KeyPairGenerator.getInstance(AndroidKeyPairGenerator.NAME);
         }
     
    -    public void testKeyPairGenerator_Initialize_Params_Success() throws Exception {
    -        mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
    -                TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
    +    public void testKeyPairGenerator_Initialize_Params_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
    +        mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
    +                .setAlias(TEST_ALIAS_1)
    +                .setSubject(TEST_DN_1)
    +                .setSerialNumber(TEST_SERIAL_1)
    +                .setStartDate(NOW)
    +                .setEndDate(NOW_PLUS_10_YEARS)
    +                .setEncryptionRequired()
    +                .build());
         }
     
    -    public void testKeyPairGenerator_Initialize_KeySize_Failure() throws Exception {
    +    public void testKeyPairGenerator_Initialize_KeySize_Encrypted_Failure() throws Exception {
    +        setupPassword();
    +
             try {
                 mGenerator.initialize(1024);
                 fail("KeyPairGenerator should not support setting the key size");
    @@ -87,7 +100,10 @@
             }
         }
     
    -    public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Failure() throws Exception {
    +    public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Encrypted_Failure()
    +            throws Exception {
    +        setupPassword();
    +
             try {
                 mGenerator.initialize(1024, new SecureRandom());
                 fail("KeyPairGenerator should not support setting the key size");
    @@ -95,14 +111,48 @@
             }
         }
     
    -    public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Failure() throws Exception {
    -        mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
    -                TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS), new SecureRandom());
    +    public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Encrypted_Failure()
    +            throws Exception {
    +        setupPassword();
    +
    +        mGenerator.initialize(
    +                new AndroidKeyPairGeneratorSpec.Builder(getContext())
    +                        .setAlias(TEST_ALIAS_1)
    +                        .setSubject(TEST_DN_1)
    +                        .setSerialNumber(TEST_SERIAL_1)
    +                        .setStartDate(NOW)
    +                        .setEndDate(NOW_PLUS_10_YEARS)
    +                        .setEncryptionRequired()
    +                        .build(),
    +                new SecureRandom());
         }
     
    -    public void testKeyPairGenerator_GenerateKeyPair_Success() throws Exception {
    -        mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
    -                TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
    +    public void testKeyPairGenerator_GenerateKeyPair_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
    +        mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
    +                .setAlias(TEST_ALIAS_1)
    +                .setSubject(TEST_DN_1)
    +                .setSerialNumber(TEST_SERIAL_1)
    +                .setStartDate(NOW)
    +                .setEndDate(NOW_PLUS_10_YEARS)
    +                .setEncryptionRequired()
    +                .build());
    +
    +        final KeyPair pair = mGenerator.generateKeyPair();
    +        assertNotNull("The KeyPair returned should not be null", pair);
    +
    +        assertKeyPairCorrect(pair, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS);
    +    }
    +
    +    public void testKeyPairGenerator_GenerateKeyPair_Unencrypted_Success() throws Exception {
    +        mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
    +                .setAlias(TEST_ALIAS_1)
    +                .setSubject(TEST_DN_1)
    +                .setSerialNumber(TEST_SERIAL_1)
    +                .setStartDate(NOW)
    +                .setEndDate(NOW_PLUS_10_YEARS)
    +                .build());
     
             final KeyPair pair = mGenerator.generateKeyPair();
             assertNotNull("The KeyPair returned should not be null", pair);
    @@ -113,8 +163,13 @@
         public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception {
             // Generate the first key
             {
    -            mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
    -                    TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
    +            mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
    +                    .setAlias(TEST_ALIAS_1)
    +                    .setSubject(TEST_DN_1)
    +                    .setSerialNumber(TEST_SERIAL_1)
    +                    .setStartDate(NOW)
    +                    .setEndDate(NOW_PLUS_10_YEARS)
    +                    .build());
                 final KeyPair pair1 = mGenerator.generateKeyPair();
                 assertNotNull("The KeyPair returned should not be null", pair1);
                 assertKeyPairCorrect(pair1, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW,
    @@ -123,8 +178,13 @@
     
             // Replace the original key
             {
    -            mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_2,
    -                    TEST_DN_2, TEST_SERIAL_2, NOW, NOW_PLUS_10_YEARS));
    +            mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
    +                    .setAlias(TEST_ALIAS_2)
    +                    .setSubject(TEST_DN_2)
    +                    .setSerialNumber(TEST_SERIAL_2)
    +                    .setStartDate(NOW)
    +                    .setEndDate(NOW_PLUS_10_YEARS)
    +                    .build());
                 final KeyPair pair2 = mGenerator.generateKeyPair();
                 assertNotNull("The KeyPair returned should not be null", pair2);
                 assertKeyPairCorrect(pair2, TEST_ALIAS_2, TEST_DN_2, TEST_SERIAL_2, NOW,
    @@ -132,6 +192,49 @@
             }
         }
     
    +    public void testKeyPairGenerator_GenerateKeyPair_Replaced_UnencryptedToEncrypted_Success()
    +            throws Exception {
    +        // Generate the first key
    +        {
    +            mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
    +                    .setAlias(TEST_ALIAS_1)
    +                    .setSubject(TEST_DN_1)
    +                    .setSerialNumber(TEST_SERIAL_1)
    +                    .setStartDate(NOW)
    +                    .setEndDate(NOW_PLUS_10_YEARS)
    +                    .build());
    +            final KeyPair pair1 = mGenerator.generateKeyPair();
    +            assertNotNull("The KeyPair returned should not be null", pair1);
    +            assertKeyPairCorrect(pair1, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW,
    +                    NOW_PLUS_10_YEARS);
    +        }
    +
    +        // Attempt to replace previous key
    +        {
    +            mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
    +                    .setAlias(TEST_ALIAS_1)
    +                    .setSubject(TEST_DN_2)
    +                    .setSerialNumber(TEST_SERIAL_2)
    +                    .setStartDate(NOW)
    +                    .setEndDate(NOW_PLUS_10_YEARS)
    +                    .setEncryptionRequired()
    +                    .build());
    +            try {
    +                mGenerator.generateKeyPair();
    +                fail("Should not be able to generate encrypted key while not initialized");
    +            } catch (IllegalStateException expected) {
    +            }
    +
    +            assertTrue(mAndroidKeyStore.password("1111"));
    +            assertTrue(mAndroidKeyStore.isUnlocked());
    +
    +            final KeyPair pair2 = mGenerator.generateKeyPair();
    +            assertNotNull("The KeyPair returned should not be null", pair2);
    +            assertKeyPairCorrect(pair2, TEST_ALIAS_1, TEST_DN_2, TEST_SERIAL_2, NOW,
    +                    NOW_PLUS_10_YEARS);
    +        }
    +    }
    +
         private void assertKeyPairCorrect(KeyPair pair, String alias, X500Principal dn,
                 BigInteger serial, Date start, Date end) throws Exception {
             final PublicKey pubKey = pair.getPublic();
    @@ -163,10 +266,10 @@
             assertEquals("The Serial should be the one passed into the params", serial,
                     x509userCert.getSerialNumber());
     
    -        assertEquals("The notBefore date should be the one passed into the params", start,
    +        assertDateEquals("The notBefore date should be the one passed into the params", start,
                     x509userCert.getNotBefore());
     
    -        assertEquals("The notAfter date should be the one passed into the params", end,
    +        assertDateEquals("The notAfter date should be the one passed into the params", end,
                     x509userCert.getNotAfter());
     
             x509userCert.verify(pubKey);
    @@ -178,4 +281,13 @@
             assertNotNull("The keystore should return the public key for the generated key",
                     pubKeyBytes);
         }
    +
    +    private static void assertDateEquals(String message, Date date1, Date date2) throws Exception {
    +        SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss");
    +
    +        String result1 = formatter.format(date1);
    +        String result2 = formatter.format(date2);
    +
    +        assertEquals(message, result1, result2);
    +    }
     }
    
    diff --git a/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
    index 8928e06..507d41c 100644
    --- a/keystore/tests/src/android/security/AndroidKeyStoreTest.java
    +++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
    
    @@ -469,12 +469,14 @@
             assertTrue(mAndroidKeyStore.reset());
             assertFalse(mAndroidKeyStore.isUnlocked());
     
    +        mKeyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
    +    }
    +
    +    private void setupPassword() {
             assertTrue(mAndroidKeyStore.password("1111"));
             assertTrue(mAndroidKeyStore.isUnlocked());
     
             assertEquals(0, mAndroidKeyStore.saw("").length);
    -
    -        mKeyStore = java.security.KeyStore.getInstance(AndroidKeyStore.NAME);
         }
     
         private void assertAliases(final String[] expectedAliases) throws KeyStoreException {
    @@ -495,21 +497,27 @@
                     expectedAliases.length, count);
         }
     
    -    public void testKeyStore_Aliases_Success() throws Exception {
    +    public void testKeyStore_Aliases_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertAliases(new String[] {});
     
    -        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1));
    +        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertAliases(new String[] { TEST_ALIAS_1 });
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 });
         }
     
    -    public void testKeyStore_Aliases_NotInitialized_Failure() throws Exception {
    +    public void testKeyStore_Aliases_NotInitialized_Encrypted_Failure() throws Exception {
    +        setupPassword();
    +
             try {
                 mKeyStore.aliases();
                 fail("KeyStore should throw exception when not initialized");
    @@ -517,16 +525,20 @@
             }
         }
     
    -    public void testKeyStore_ContainsAliases_PrivateAndCA_Success() throws Exception {
    +    public void testKeyStore_ContainsAliases_PrivateAndCA_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertAliases(new String[] {});
     
    -        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1));
    +        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should contain generated private key", mKeyStore.containsAlias(TEST_ALIAS_1));
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2));
     
    @@ -534,34 +546,45 @@
                     mKeyStore.containsAlias(TEST_ALIAS_3));
         }
     
    -    public void testKeyStore_ContainsAliases_CAOnly_Success() throws Exception {
    +    public void testKeyStore_ContainsAliases_CAOnly_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2));
         }
     
    -    public void testKeyStore_ContainsAliases_NonExistent_Failure() throws Exception {
    +    public void testKeyStore_ContainsAliases_NonExistent_Encrypted_Failure() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertFalse("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_1));
         }
     
    -    public void testKeyStore_DeleteEntry_Success() throws Exception {
    +    public void testKeyStore_DeleteEntry_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             // TEST_ALIAS_1
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             // TEST_ALIAS_2
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             // TEST_ALIAS_3
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_3, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_3, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 });
     
    @@ -578,30 +601,39 @@
             assertAliases(new String[] { });
         }
     
    -    public void testKeyStore_DeleteEntry_EmptyStore_Success() throws Exception {
    +    public void testKeyStore_DeleteEntry_EmptyStore_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             // Should not throw when a non-existent entry is requested for delete.
             mKeyStore.deleteEntry(TEST_ALIAS_1);
         }
     
    -    public void testKeyStore_DeleteEntry_NonExistent_Success() throws Exception {
    +    public void testKeyStore_DeleteEntry_NonExistent_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             // TEST_ALIAS_1
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             // Should not throw when a non-existent entry is requested for delete.
             mKeyStore.deleteEntry(TEST_ALIAS_2);
         }
     
    -    public void testKeyStore_GetCertificate_Single_Success() throws Exception {
    +    public void testKeyStore_GetCertificate_Single_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertAliases(new String[] { TEST_ALIAS_1 });
     
    @@ -618,17 +650,22 @@
             assertEquals("Actual and retrieved certificates should be the same", actual, retrieved);
         }
     
    -    public void testKeyStore_GetCertificate_NonExist_Failure() throws Exception {
    +    public void testKeyStore_GetCertificate_NonExist_Encrypted_Failure() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertNull("Certificate should not exist in keystore",
                     mKeyStore.getCertificate(TEST_ALIAS_1));
         }
     
    -    public void testKeyStore_GetCertificateAlias_CAEntry_Success() throws Exception {
    +    public void testKeyStore_GetCertificateAlias_CAEntry_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             CertificateFactory f = CertificateFactory.getInstance("X.509");
             Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
    @@ -637,13 +674,18 @@
                     mKeyStore.getCertificateAlias(actual));
         }
     
    -    public void testKeyStore_GetCertificateAlias_PrivateKeyEntry_Success() throws Exception {
    +    public void testKeyStore_GetCertificateAlias_PrivateKeyEntry_Encrypted_Success()
    +            throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             CertificateFactory f = CertificateFactory.getInstance("X.509");
             Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
    @@ -652,18 +694,23 @@
                     mKeyStore.getCertificateAlias(actual));
         }
     
    -    public void testKeyStore_GetCertificateAlias_CAEntry_WithPrivateKeyUsingCA_Success()
    +    public void testKeyStore_GetCertificateAlias_CAEntry_WithPrivateKeyUsingCA_Encrypted_Success()
                 throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             // Insert TrustedCertificateEntry with CA name
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             // Insert PrivateKeyEntry that uses the same CA
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             CertificateFactory f = CertificateFactory.getInstance("X.509");
             Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
    @@ -672,7 +719,10 @@
                     mKeyStore.getCertificateAlias(actual));
         }
     
    -    public void testKeyStore_GetCertificateAlias_NonExist_Empty_Failure() throws Exception {
    +    public void testKeyStore_GetCertificateAlias_NonExist_Empty_Encrypted_Failure()
    +            throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             CertificateFactory f = CertificateFactory.getInstance("X.509");
    @@ -682,10 +732,13 @@
                     mKeyStore.getCertificateAlias(actual));
         }
     
    -    public void testKeyStore_GetCertificateAlias_NonExist_Failure() throws Exception {
    +    public void testKeyStore_GetCertificateAlias_NonExist_Encrypted_Failure() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             CertificateFactory f = CertificateFactory.getInstance("X.509");
             Certificate userCert = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
    @@ -694,13 +747,17 @@
                     mKeyStore.getCertificateAlias(userCert));
         }
     
    -    public void testKeyStore_GetCertificateChain_SingleLength_Success() throws Exception {
    +    public void testKeyStore_GetCertificateChain_SingleLength_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             CertificateFactory cf = CertificateFactory.getInstance("X.509");
             Certificate[] expected = new Certificate[2];
    @@ -720,20 +777,26 @@
                     mKeyStore.getCertificateChain(TEST_ALIAS_2));
         }
     
    -    public void testKeyStore_GetCertificateChain_NonExist_Failure() throws Exception {
    +    public void testKeyStore_GetCertificateChain_NonExist_Encrypted_Failure() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertNull("Stored certificate alias should not be found",
                     mKeyStore.getCertificateChain(TEST_ALIAS_1));
         }
     
    -    public void testKeyStore_GetCreationDate_PrivateKeyEntry_Success() throws Exception {
    +    public void testKeyStore_GetCreationDate_PrivateKeyEntry_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             Date now = new Date();
             Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
    @@ -745,10 +808,33 @@
             assertTrue("Time should be close to current time", actual.after(expectedAfter));
         }
     
    -    public void testKeyStore_GetCreationDate_CAEntry_Success() throws Exception {
    +    public void testKeyStore_GetCreationDate_PrivateKeyEntry_Unencrypted_Success() throws Exception {
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
    +
    +        Date now = new Date();
    +        Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
    +
    +        Date expectedAfter = new Date(now.getTime() - SLOP_TIME_MILLIS);
    +        Date expectedBefore = new Date(now.getTime() + SLOP_TIME_MILLIS);
    +
    +        assertTrue("Time should be close to current time", actual.before(expectedBefore));
    +        assertTrue("Time should be close to current time", actual.after(expectedAfter));
    +    }
    +
    +    public void testKeyStore_GetCreationDate_CAEntry_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
    +        mKeyStore.load(null, null);
    +
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             Date now = new Date();
             Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
    @@ -761,13 +847,37 @@
             assertTrue("Time should be close to current time", actual.after(expectedAfter));
         }
     
    -    public void testKeyStore_GetEntry_NullParams_Success() throws Exception {
    +    public void testKeyStore_GetEntry_NullParams_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +
    +        Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
    +        assertNotNull("Entry should exist", entry);
    +
    +        assertTrue("Should be a PrivateKeyEntry", entry instanceof PrivateKeyEntry);
    +
    +        PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
    +
    +        assertPrivateKeyEntryEquals(keyEntry, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
    +    }
    +
    +    public void testKeyStore_GetEntry_NullParams_Unencrypted_Success() throws Exception {
    +        mKeyStore.load(null, null);
    +
    +        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
     
             Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
             assertNotNull("Entry should exist", entry);
    @@ -801,8 +911,9 @@
     
         private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey,
                 Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception {
    -        assertEquals("Returned PrivateKey should be what we inserted", expectedKey,
    -                keyEntry.getPrivateKey());
    +        assertEquals("Returned PrivateKey should be what we inserted",
    +                ((RSAPrivateKey) expectedKey).getModulus(),
    +                ((RSAPrivateKey) keyEntry.getPrivateKey()).getModulus());
     
             assertEquals("Returned Certificate should be what we inserted", expectedCert,
                     keyEntry.getCertificate());
    @@ -823,20 +934,33 @@
             }
         }
     
    -    public void testKeyStore_GetEntry_Nonexistent_NullParams_Failure() throws Exception {
    +    public void testKeyStore_GetEntry_Nonexistent_NullParams_Encrypted_Failure() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertNull("A non-existent entry should return null",
                     mKeyStore.getEntry(TEST_ALIAS_1, null));
         }
     
    -    public void testKeyStore_GetKey_NoPassword_Success() throws Exception {
    +    public void testKeyStore_GetEntry_Nonexistent_NullParams_Unencrypted_Failure() throws Exception {
    +        mKeyStore.load(null, null);
    +
    +        assertNull("A non-existent entry should return null",
    +                mKeyStore.getEntry(TEST_ALIAS_1, null));
    +    }
    +
    +    public void testKeyStore_GetKey_NoPassword_Encrypted_Success() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
             assertNotNull("Key should exist", key);
    @@ -848,89 +972,143 @@
             KeyFactory keyFact = KeyFactory.getInstance("RSA");
             PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
     
    -        assertEquals("Inserted key should be same as retrieved key", actualKey, expectedKey);
    +        assertEquals("Inserted key should be same as retrieved key",
    +                ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
         }
     
    -    public void testKeyStore_GetKey_Certificate_Failure() throws Exception {
    +    public void testKeyStore_GetKey_NoPassword_Unencrypted_Success() throws Exception {
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
    +
    +        Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
    +        assertNotNull("Key should exist", key);
    +
    +        assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
    +
    +        RSAPrivateKey actualKey = (RSAPrivateKey) key;
    +
    +        KeyFactory keyFact = KeyFactory.getInstance("RSA");
    +        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
    +
    +        assertEquals("Inserted key should be same as retrieved key",
    +                ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
    +    }
    +
    +    public void testKeyStore_GetKey_Certificate_Encrypted_Failure() throws Exception {
    +        setupPassword();
    +
    +        mKeyStore.load(null, null);
    +
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertNull("Certificate entries should return null", mKeyStore.getKey(TEST_ALIAS_1, null));
         }
     
    -    public void testKeyStore_GetKey_NonExistent_Failure() throws Exception {
    +    public void testKeyStore_GetKey_NonExistent_Encrypted_Failure() throws Exception {
    +        setupPassword();
    +
             mKeyStore.load(null, null);
     
             assertNull("A non-existent entry should return null", mKeyStore.getKey(TEST_ALIAS_1, null));
         }
     
    -    public void testKeyStore_GetProvider_Success() throws Exception {
    +    public void testKeyStore_GetProvider_Encrypted_Success() throws Exception {
    +        assertEquals(AndroidKeyStoreProvider.PROVIDER_NAME, mKeyStore.getProvider().getName());
    +        setupPassword();
             assertEquals(AndroidKeyStoreProvider.PROVIDER_NAME, mKeyStore.getProvider().getName());
         }
     
    -    public void testKeyStore_GetType_Success() throws Exception {
    +    public void testKeyStore_GetType_Encrypted_Success() throws Exception {
    +        assertEquals(AndroidKeyStore.NAME, mKeyStore.getType());
    +        setupPassword();
             assertEquals(AndroidKeyStore.NAME, mKeyStore.getType());
         }
     
    -    public void testKeyStore_IsCertificateEntry_CA_Success() throws Exception {
    +    public void testKeyStore_IsCertificateEntry_CA_Encrypted_Success() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should return true for CA certificate",
                     mKeyStore.isCertificateEntry(TEST_ALIAS_1));
         }
     
    -    public void testKeyStore_IsCertificateEntry_PrivateKey_Failure() throws Exception {
    +    public void testKeyStore_IsCertificateEntry_PrivateKey_Encrypted_Failure() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertFalse("Should return false for PrivateKeyEntry",
                     mKeyStore.isCertificateEntry(TEST_ALIAS_1));
         }
     
    -    public void testKeyStore_IsCertificateEntry_NonExist_Failure() throws Exception {
    +    public void testKeyStore_IsCertificateEntry_NonExist_Encrypted_Failure() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             assertFalse("Should return false for non-existent entry",
                     mKeyStore.isCertificateEntry(TEST_ALIAS_1));
         }
     
    -    public void testKeyStore_IsKeyEntry_PrivateKey_Success() throws Exception {
    +    public void testKeyStore_IsCertificateEntry_NonExist_Unencrypted_Failure() throws Exception {
    +        mKeyStore.load(null, null);
    +
    +        assertFalse("Should return false for non-existent entry",
    +                mKeyStore.isCertificateEntry(TEST_ALIAS_1));
    +    }
    +
    +    public void testKeyStore_IsKeyEntry_PrivateKey_Encrypted_Success() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should return true for PrivateKeyEntry", mKeyStore.isKeyEntry(TEST_ALIAS_1));
         }
     
    -    public void testKeyStore_IsKeyEntry_CA_Failure() throws Exception {
    +    public void testKeyStore_IsKeyEntry_CA_Encrypted_Failure() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertFalse("Should return false for CA certificate", mKeyStore.isKeyEntry(TEST_ALIAS_1));
         }
     
    -    public void testKeyStore_IsKeyEntry_NonExist_Failure() throws Exception {
    +    public void testKeyStore_IsKeyEntry_NonExist_Encrypted_Failure() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             assertFalse("Should return false for non-existent entry",
                     mKeyStore.isKeyEntry(TEST_ALIAS_1));
         }
     
    -    public void testKeyStore_SetCertificate_CA_Success() throws Exception {
    +    public void testKeyStore_SetCertificate_CA_Encrypted_Success() throws Exception {
             final CertificateFactory f = CertificateFactory.getInstance("X.509");
             final Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
     
    +        setupPassword();
             mKeyStore.load(null, null);
     
             mKeyStore.setCertificateEntry(TEST_ALIAS_1, actual);
    @@ -942,10 +1120,12 @@
                     retrieved);
         }
     
    -    public void testKeyStore_SetCertificate_CAExists_Overwrite_Success() throws Exception {
    +    public void testKeyStore_SetCertificate_CAExists_Overwrite_Encrypted_Success() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertAliases(new String[] { TEST_ALIAS_1 });
     
    @@ -958,13 +1138,16 @@
             assertAliases(new String[] { TEST_ALIAS_1 });
         }
     
    -    public void testKeyStore_SetCertificate_PrivateKeyExists_Failure() throws Exception {
    +    public void testKeyStore_SetCertificate_PrivateKeyExists_Encrypted_Failure() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
    -                FAKE_KEY_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +                FAKE_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertAliases(new String[] { TEST_ALIAS_1 });
     
    @@ -978,7 +1161,8 @@
             }
         }
     
    -    public void testKeyStore_SetEntry_PrivateKeyEntry_Success() throws Exception {
    +    public void testKeyStore_SetEntry_PrivateKeyEntry_Encrypted_Success() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             KeyFactory keyFact = KeyFactory.getInstance("RSA");
    @@ -1005,8 +1189,63 @@
             assertPrivateKeyEntryEquals(actual, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
         }
     
    -    public void testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_PrivateKeyEntry_Success()
    +    public void testKeyStore_SetEntry_PrivateKeyEntry_Unencrypted_Success() throws Exception {
    +        mKeyStore.load(null, null);
    +
    +        KeyFactory keyFact = KeyFactory.getInstance("RSA");
    +        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
    +
    +        final CertificateFactory f = CertificateFactory.getInstance("X.509");
    +
    +        final Certificate[] expectedChain = new Certificate[2];
    +        expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
    +        expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
    +
    +        PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
    +
    +        mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
    +
    +        Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
    +        assertNotNull("Retrieved entry should exist", actualEntry);
    +
    +        assertTrue("Retrieved entry should be of type PrivateKeyEntry",
    +                actualEntry instanceof PrivateKeyEntry);
    +
    +        PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
    +
    +        assertPrivateKeyEntryEquals(actual, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
    +    }
    +
    +    public void testKeyStore_SetEntry_PrivateKeyEntry_Params_Unencrypted_Failure() throws Exception {
    +        mKeyStore.load(null, null);
    +
    +        KeyFactory keyFact = KeyFactory.getInstance("RSA");
    +        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
    +
    +        final CertificateFactory f = CertificateFactory.getInstance("X.509");
    +
    +        final Certificate[] expectedChain = new Certificate[2];
    +        expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
    +        expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
    +
    +        PrivateKeyEntry entry = new PrivateKeyEntry(expectedKey, expectedChain);
    +
    +        try {
    +            mKeyStore.setEntry(TEST_ALIAS_1, entry,
    +                    new AndroidKeyStoreParameter.Builder(getContext())
    +                    .setEncryptionRequired()
    +                    .build());
    +            fail("Shouldn't be able to insert encrypted entry when KeyStore uninitialized");
    +        } catch (KeyStoreException expected) {
    +        }
    +
    +        assertNull(mKeyStore.getEntry(TEST_ALIAS_1, null));
    +    }
    +
    +    public void
    +            testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_PrivateKeyEntry_Encrypted_Success()
                 throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             final KeyFactory keyFact = KeyFactory.getInstance("RSA");
    @@ -1060,7 +1299,9 @@
             }
         }
     
    -    public void testKeyStore_SetEntry_CAEntry_Overwrites_PrivateKeyEntry_Success() throws Exception {
    +    public void testKeyStore_SetEntry_CAEntry_Overwrites_PrivateKeyEntry_Encrypted_Success()
    +            throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             final CertificateFactory f = CertificateFactory.getInstance("X.509");
    @@ -1104,7 +1345,9 @@
             }
         }
     
    -    public void testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_CAEntry_Success() throws Exception {
    +    public void testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_CAEntry_Encrypted_Success()
    +            throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             final CertificateFactory f = CertificateFactory.getInstance("X.509");
    @@ -1148,8 +1391,11 @@
             }
         }
     
    -    public void testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_ShortPrivateKeyEntry_Success()
    +    public
    +            void
    +            testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_ShortPrivateKeyEntry_Encrypted_Success()
                 throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             final CertificateFactory f = CertificateFactory.getInstance("X.509");
    @@ -1198,7 +1444,9 @@
             }
         }
     
    -    public void testKeyStore_SetEntry_CAEntry_Overwrites_CAEntry_Success() throws Exception {
    +    public void testKeyStore_SetEntry_CAEntry_Overwrites_CAEntry_Encrypted_Success()
    +            throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             final CertificateFactory f = CertificateFactory.getInstance("X.509");
    @@ -1239,7 +1487,8 @@
             }
         }
     
    -    public void testKeyStore_SetKeyEntry_ProtectedKey_Failure() throws Exception {
    +    public void testKeyStore_SetKeyEntry_ProtectedKey_Encrypted_Failure() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             final CertificateFactory f = CertificateFactory.getInstance("X.509");
    @@ -1259,7 +1508,8 @@
             }
         }
     
    -    public void testKeyStore_SetKeyEntry_Success() throws Exception {
    +    public void testKeyStore_SetKeyEntry_Encrypted_Success() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             final CertificateFactory f = CertificateFactory.getInstance("X.509");
    @@ -1285,7 +1535,8 @@
             assertPrivateKeyEntryEquals(actual, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
         }
     
    -    public void testKeyStore_SetKeyEntry_Replaced_Success() throws Exception {
    +    public void testKeyStore_SetKeyEntry_Replaced_Encrypted_Success() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             final CertificateFactory f = CertificateFactory.getInstance("X.509");
    @@ -1376,13 +1627,15 @@
             return cert;
         }
     
    -    public void testKeyStore_SetKeyEntry_ReplacedChain_Success() throws Exception {
    +    public void testKeyStore_SetKeyEntry_ReplacedChain_Encrypted_Success() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             // Create key #1
             {
                 final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
    -            assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
    +            assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
    +                    KeyStore.FLAG_ENCRYPTED));
     
                 Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
     
    @@ -1394,7 +1647,7 @@
                         TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
     
                 assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
    -                    expectedCert.getEncoded()));
    +                    expectedCert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
                 Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
     
    @@ -1429,32 +1682,35 @@
             }
         }
     
    -    public void testKeyStore_SetKeyEntry_ReplacedChain_DifferentPrivateKey_Failure()
    +    public void testKeyStore_SetKeyEntry_ReplacedChain_DifferentPrivateKey_Encrypted_Failure()
                 throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             // Create key #1
             {
                 final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
    -            assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
    +            assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
    +                    KeyStore.FLAG_ENCRYPTED));
     
                 X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
                         TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
     
                 assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
    -                    cert.getEncoded()));
    +                    cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
             }
     
             // Create key #2
             {
                 final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_2;
    -            assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
    +            assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
    +                    KeyStore.FLAG_ENCRYPTED));
     
                 X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2,
                         TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
     
                 assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_2,
    -                    cert.getEncoded()));
    +                    cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
             }
     
             // Replace key #1 with key #2
    @@ -1472,20 +1728,64 @@
             }
         }
     
    -    public void testKeyStore_Size_Success() throws Exception {
    +    public void testKeyStore_SetKeyEntry_ReplacedChain_UnencryptedToEncrypted_Failure()
    +            throws Exception {
             mKeyStore.load(null, null);
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
    +        // Create key #1
    +        {
    +            final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
    +            assertTrue(mAndroidKeyStore.generate(privateKeyAlias,
    +                    android.security.KeyStore.UID_SELF, android.security.KeyStore.FLAG_NONE));
    +
    +            X509Certificate cert =
    +                    generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1, TEST_DN_1,
    +                            NOW, NOW_PLUS_10_YEARS);
    +
    +            assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
    +                    cert.getEncoded(), android.security.KeyStore.UID_SELF,
    +                    android.security.KeyStore.FLAG_NONE));
    +        }
    +
    +        // Replace with one that requires encryption
    +        {
    +            Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
    +
    +            try {
    +                mKeyStore.setEntry(TEST_ALIAS_1, entry, new AndroidKeyStoreParameter.Builder(
    +                        getContext()).setEncryptionRequired().build());
    +                fail("Should not allow setting of Entry without unlocked keystore");
    +            } catch (KeyStoreException success) {
    +            }
    +
    +            assertTrue(mAndroidKeyStore.password("1111"));
    +            assertTrue(mAndroidKeyStore.isUnlocked());
    +
    +            mKeyStore.setEntry(TEST_ALIAS_1, entry,
    +                    new AndroidKeyStoreParameter.Builder(getContext())
    +                            .setEncryptionRequired()
    +                            .build());
    +        }
    +    }
    +
    +    public void testKeyStore_Size_Encrypted_Success() throws Exception {
    +        setupPassword();
    +        mKeyStore.load(null, null);
    +
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertEquals("The keystore size should match expected", 1, mKeyStore.size());
             assertAliases(new String[] { TEST_ALIAS_1 });
     
    -        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
    +        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertEquals("The keystore size should match expected", 2, mKeyStore.size());
             assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 });
     
    -        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3));
    +        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3,
    +                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertEquals("The keystore size should match expected", 3, mKeyStore.size());
             assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 });
    @@ -1501,7 +1801,8 @@
             assertAliases(new String[] { TEST_ALIAS_2 });
         }
     
    -    public void testKeyStore_Store_LoadStoreParam_Failure() throws Exception {
    +    public void testKeyStore_Store_LoadStoreParam_Encrypted_Failure() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             try {
    @@ -1511,7 +1812,7 @@
             }
         }
     
    -    public void testKeyStore_Load_InputStreamSupplied_Failure() throws Exception {
    +    public void testKeyStore_Load_InputStreamSupplied_Encrypted_Failure() throws Exception {
             byte[] buf = "FAKE KEYSTORE".getBytes();
             ByteArrayInputStream is = new ByteArrayInputStream(buf);
     
    @@ -1522,7 +1823,7 @@
             }
         }
     
    -    public void testKeyStore_Load_PasswordSupplied_Failure() throws Exception {
    +    public void testKeyStore_Load_PasswordSupplied_Encrypted_Failure() throws Exception {
             try {
                 mKeyStore.load(null, "password".toCharArray());
                 fail("Should throw IllegalArgumentException when password is supplied");
    @@ -1530,7 +1831,8 @@
             }
         }
     
    -    public void testKeyStore_Store_OutputStream_Failure() throws Exception {
    +    public void testKeyStore_Store_OutputStream_Encrypted_Failure() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             OutputStream sink = new ByteArrayOutputStream();
    @@ -1549,16 +1851,18 @@
     
         private void setupKey() throws Exception {
             final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
    -        assertTrue(mAndroidKeyStore.generate(privateKeyAlias));
    +        assertTrue(mAndroidKeyStore
    +                .generate(privateKeyAlias, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1,
                     TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
     
             assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
    -                cert.getEncoded()));
    +                cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         }
     
    -    public void testKeyStore_KeyOperations_Wrap_Success() throws Exception {
    +    public void testKeyStore_KeyOperations_Wrap_Encrypted_Success() throws Exception {
    +        setupPassword();
             mKeyStore.load(null, null);
     
             setupKey();
    
    diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
    index 1de1eaf..815f4ac 100644
    --- a/keystore/tests/src/android/security/KeyStoreTest.java
    +++ b/keystore/tests/src/android/security/KeyStoreTest.java
    
    @@ -142,42 +142,51 @@
             assertNull(mKeyStore.get(TEST_KEYNAME));
             mKeyStore.password(TEST_PASSWD);
             assertNull(mKeyStore.get(TEST_KEYNAME));
    -        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
    +        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
    +                KeyStore.FLAG_ENCRYPTED));
             assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
         }
     
         public void testPut() throws Exception {
             assertNull(mKeyStore.get(TEST_KEYNAME));
    -        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
    +        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
    +                KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_KEYNAME));
             mKeyStore.password(TEST_PASSWD);
    -        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
    +        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
    +                KeyStore.FLAG_ENCRYPTED));
             assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
         }
     
         public void testPut_grantedUid_Wifi() throws Exception {
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    -        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
    +        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
    +                KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
             mKeyStore.password(TEST_PASSWD);
    -        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
    +        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
    +                KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         }
     
         public void testPut_ungrantedUid_Bluetooth() throws Exception {
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
    -        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
    +        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
    +                KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
             mKeyStore.password(TEST_PASSWD);
    -        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
    +        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
    +                KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
         }
     
         public void testI18n() throws Exception {
    -        assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE));
    +        assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE, KeyStore.UID_SELF,
    +                KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_I18N_KEY));
             mKeyStore.password(TEST_I18N_KEY);
    -        assertTrue(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE));
    +        assertTrue(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE, KeyStore.UID_SELF,
    +                KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_I18N_KEY));
         }
     
    @@ -186,7 +195,8 @@
             mKeyStore.password(TEST_PASSWD);
             assertFalse(mKeyStore.delete(TEST_KEYNAME));
     
    -        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
    +        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
    +                KeyStore.FLAG_ENCRYPTED));
             assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
             assertTrue(mKeyStore.delete(TEST_KEYNAME));
             assertNull(mKeyStore.get(TEST_KEYNAME));
    @@ -197,7 +207,8 @@
             mKeyStore.password(TEST_PASSWD);
             assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
     
    -        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
    +        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
    +                KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
             assertTrue(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    @@ -208,7 +219,8 @@
             mKeyStore.password(TEST_PASSWD);
             assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
     
    -        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
    +        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
    +                KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
             assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
    @@ -220,7 +232,8 @@
             assertTrue(mKeyStore.password(TEST_PASSWD));
             assertFalse(mKeyStore.contains(TEST_KEYNAME));
     
    -        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
    +        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
    +                KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME));
         }
     
    @@ -230,7 +243,8 @@
             assertTrue(mKeyStore.password(TEST_PASSWD));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
     
    -        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
    +        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
    +                KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         }
     
    @@ -240,7 +254,8 @@
             assertTrue(mKeyStore.password(TEST_PASSWD));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
     
    -        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
    +        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
    +                KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
         }
     
    @@ -250,8 +265,8 @@
             assertEquals(0, emptyResult.length);
     
             mKeyStore.password(TEST_PASSWD);
    -        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE);
    -        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE);
    +        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
    +        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
     
             String[] results = mKeyStore.saw(TEST_KEYNAME);
             assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
    @@ -264,8 +279,8 @@
             assertNull(results1);
     
             mKeyStore.password(TEST_PASSWD);
    -        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE);
    -        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE);
    +        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
    +        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
     
             String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
             assertNull(results2);
    @@ -277,8 +292,8 @@
             assertEquals(0, results1.length);
     
             mKeyStore.password(TEST_PASSWD);
    -        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID);
    -        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID);
    +        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
    +        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
     
             String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
             assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
    @@ -292,8 +307,8 @@
             assertEquals(0, results1.length);
     
             mKeyStore.password(TEST_PASSWD);
    -        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID);
    -        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID);
    +        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED);
    +        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED);
     
             String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
             assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
    @@ -324,7 +339,7 @@
             assertTrue(mKeyStore.isEmpty());
             mKeyStore.password(TEST_PASSWD);
             assertTrue(mKeyStore.isEmpty());
    -        mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE);
    +        mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
             assertFalse(mKeyStore.isEmpty());
             mKeyStore.reset();
             assertTrue(mKeyStore.isEmpty());
    @@ -332,20 +347,21 @@
     
         public void testGenerate_NotInitialized_Fail() throws Exception {
             assertFalse("Should fail when keystore is not initialized",
    -                mKeyStore.generate(TEST_KEYNAME));
    +                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         }
     
         public void testGenerate_Locked_Fail() throws Exception {
             mKeyStore.password(TEST_PASSWD);
             mKeyStore.lock();
    -        assertFalse("Should fail when keystore is locked", mKeyStore.generate(TEST_KEYNAME));
    +        assertFalse("Should fail when keystore is locked",
    +                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
         }
     
         public void testGenerate_Success() throws Exception {
             assertTrue(mKeyStore.password(TEST_PASSWD));
     
             assertTrue("Should be able to generate key when unlocked",
    -                mKeyStore.generate(TEST_KEYNAME));
    +                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         }
    @@ -354,7 +370,7 @@
             assertTrue(mKeyStore.password(TEST_PASSWD));
     
             assertTrue("Should be able to generate key when unlocked",
    -                mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID));
    +                mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
             assertFalse(mKeyStore.contains(TEST_KEYNAME));
         }
    @@ -362,7 +378,7 @@
         public void testGenerate_ungrantedUid_Bluetooth_Failure() throws Exception {
             assertTrue(mKeyStore.password(TEST_PASSWD));
     
    -        assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID));
    +        assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID, KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
             assertFalse(mKeyStore.contains(TEST_KEYNAME));
    @@ -371,8 +387,8 @@
         public void testImport_Success() throws Exception {
             assertTrue(mKeyStore.password(TEST_PASSWD));
     
    -        assertTrue("Should be able to import key when unlocked",
    -                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
    +        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
    +                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         }
    @@ -380,8 +396,8 @@
         public void testImport_grantedUid_Wifi_Success() throws Exception {
             assertTrue(mKeyStore.password(TEST_PASSWD));
     
    -        assertTrue("Should be able to import key when unlocked",
    -                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.WIFI_UID));
    +        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
    +                PRIVKEY_BYTES, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
             assertFalse(mKeyStore.contains(TEST_KEYNAME));
         }
    @@ -389,7 +405,8 @@
         public void testImport_ungrantedUid_Bluetooth_Failure() throws Exception {
             assertTrue(mKeyStore.password(TEST_PASSWD));
     
    -        assertFalse(mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.BLUETOOTH_UID));
    +        assertFalse(mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.BLUETOOTH_UID,
    +                KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
             assertFalse(mKeyStore.contains(TEST_KEYNAME));
    @@ -398,8 +415,8 @@
         public void testImport_Failure_BadEncoding() throws Exception {
             mKeyStore.password(TEST_PASSWD);
     
    -        assertFalse("Invalid DER-encoded key should not be imported",
    -                mKeyStore.importKey(TEST_KEYNAME, TEST_DATA));
    +        assertFalse("Invalid DER-encoded key should not be imported", mKeyStore.importKey(
    +                TEST_KEYNAME, TEST_DATA, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
             assertFalse(mKeyStore.contains(TEST_KEYNAME));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         }
    @@ -407,7 +424,7 @@
         public void testSign_Success() throws Exception {
             mKeyStore.password(TEST_PASSWD);
     
    -        assertTrue(mKeyStore.generate(TEST_KEYNAME));
    +        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME));
             final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
     
    @@ -417,7 +434,7 @@
         public void testVerify_Success() throws Exception {
             mKeyStore.password(TEST_PASSWD);
     
    -        assertTrue(mKeyStore.generate(TEST_KEYNAME));
    +        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
             assertTrue(mKeyStore.contains(TEST_KEYNAME));
             final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
     
    @@ -444,7 +461,7 @@
                     mKeyStore.password(TEST_PASSWD));
     
             assertTrue("Should be able to generate key for testcase",
    -                mKeyStore.generate(TEST_KEYNAME));
    +                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should be able to grant key to other user",
                     mKeyStore.grant(TEST_KEYNAME, 0));
    @@ -453,8 +470,8 @@
         public void testGrant_Imported_Success() throws Exception {
             assertTrue("Password should work for keystore", mKeyStore.password(TEST_PASSWD));
     
    -        assertTrue("Should be able to import key for testcase",
    -                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
    +        assertTrue("Should be able to import key for testcase", mKeyStore.importKey(TEST_KEYNAME,
    +                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should be able to grant key to other user", mKeyStore.grant(TEST_KEYNAME, 0));
         }
    @@ -477,7 +494,7 @@
                     mKeyStore.password(TEST_PASSWD));
     
             assertTrue("Should be able to generate key for testcase",
    -                mKeyStore.generate(TEST_KEYNAME));
    +                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should be able to grant key to other user",
                     mKeyStore.grant(TEST_KEYNAME, 0));
    @@ -490,8 +507,8 @@
             assertTrue("Password should work for keystore",
                     mKeyStore.password(TEST_PASSWD));
     
    -        assertTrue("Should be able to import key for testcase",
    -                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
    +        assertTrue("Should be able to import key for testcase", mKeyStore.importKey(TEST_KEYNAME,
    +                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should be able to grant key to other user",
                     mKeyStore.grant(TEST_KEYNAME, 0));
    @@ -510,7 +527,7 @@
                     mKeyStore.password(TEST_PASSWD));
     
             assertTrue("Should be able to generate key for testcase",
    -                mKeyStore.generate(TEST_KEYNAME));
    +                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertFalse("Should not be able to revoke not existent grant",
                     mKeyStore.ungrant(TEST_KEYNAME, 0));
    @@ -521,7 +538,7 @@
                     mKeyStore.password(TEST_PASSWD));
     
             assertTrue("Should be able to generate key for testcase",
    -                mKeyStore.generate(TEST_KEYNAME));
    +                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should be able to grant key to other user",
                     mKeyStore.grant(TEST_KEYNAME, 0));
    @@ -538,7 +555,7 @@
                     mKeyStore.password(TEST_PASSWD));
     
             assertTrue("Should be able to generate key for testcase",
    -                mKeyStore.generate(TEST_KEYNAME));
    +                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue("Should be able to grant key to other user",
                     mKeyStore.grant(TEST_KEYNAME, 0));
    @@ -558,7 +575,7 @@
     
             assertFalse(mKeyStore.contains(TEST_KEYNAME));
     
    -        assertTrue(mKeyStore.generate(TEST_KEYNAME));
    +        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue(mKeyStore.contains(TEST_KEYNAME));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
    @@ -596,7 +613,7 @@
     
             assertFalse(mKeyStore.contains(TEST_KEYNAME));
     
    -        assertTrue(mKeyStore.generate(TEST_KEYNAME));
    +        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertTrue(mKeyStore.contains(TEST_KEYNAME));
             assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
    @@ -619,8 +636,8 @@
             assertTrue("Password should work for keystore",
                     mKeyStore.password(TEST_PASSWD));
     
    -        assertTrue("Should be able to import key when unlocked",
    -                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
    +        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
    +                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             long now = System.currentTimeMillis();
             long actual = mKeyStore.getmtime(TEST_KEYNAME);
    @@ -650,8 +667,8 @@
             assertTrue("Password should work for keystore",
                     mKeyStore.password(TEST_PASSWD));
     
    -        assertTrue("Should be able to import key when unlocked",
    -                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
    +        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
    +                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
     
             assertEquals("-1 should be returned for non-existent key",
                     -1L, mKeyStore.getmtime(TEST_KEYNAME2));
    
    diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
    index 8bd805c..b08c36b 100644
    --- a/libs/androidfw/AssetManager.cpp
    +++ b/libs/androidfw/AssetManager.cpp
    
    @@ -19,6 +19,7 @@
     //
     
     #define LOG_TAG "asset"
    +#define ATRACE_TAG ATRACE_TAG_RESOURCES
     //#define LOG_NDEBUG 0
     
     #include <androidfw/Asset.h>
    @@ -32,6 +33,9 @@
     #include <utils/threads.h>
     #include <utils/Timers.h>
     #include <utils/ZipFileRO.h>
    +#ifdef HAVE_ANDROID_OS
    +#include <cutils/trace.h>
    +#endif
     
     #include <assert.h>
     #include <dirent.h>
    @@ -51,6 +55,14 @@
         _rc; })
     #endif
     
    +#ifdef HAVE_ANDROID_OS
    +#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x)
    +#define MY_TRACE_END() ATRACE_END()
    +#else
    +#define MY_TRACE_BEGIN(x)
    +#define MY_TRACE_END()
    +#endif
    +
     using namespace android;
     
     /*
    @@ -638,6 +650,7 @@
             ResTable* sharedRes = NULL;
             bool shared = true;
             const asset_path& ap = mAssetPaths.itemAt(i);
    +        MY_TRACE_BEGIN(ap.path.string());
             Asset* idmap = openIdmapLocked(ap);
             ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
             if (ap.type != kFileTypeDirectory) {
    @@ -702,6 +715,7 @@
             if (idmap != NULL) {
                 delete idmap;
             }
    +        MY_TRACE_END();
         }
     
         if (required && !rt) ALOGW("Unable to find resources file resources.arsc");
    
    diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
    index 7b59bf2..a630ea1 100644
    --- a/libs/hwui/Android.mk
    +++ b/libs/hwui/Android.mk
    
    @@ -30,6 +30,7 @@
     		PatchCache.cpp \
     		PathCache.cpp \
     		PathTessellator.cpp \
    +		PixelBuffer.cpp \
     		Program.cpp \
     		ProgramCache.cpp \
     		RenderBufferCache.cpp \
    
    diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
    index 57d1a4f..a381a68 100644
    --- a/libs/hwui/Caches.cpp
    +++ b/libs/hwui/Caches.cpp
    
    @@ -70,6 +70,7 @@
         mCurrentPositionPointer = this;
         mCurrentPositionStride = 0;
         mCurrentTexCoordsPointer = this;
    +    mCurrentPixelBuffer = 0;
     
         mTexCoordsArrayEnabled = false;
     
    @@ -366,6 +367,28 @@
     }
     
     ///////////////////////////////////////////////////////////////////////////////
    +// PBO
    +///////////////////////////////////////////////////////////////////////////////
    +
    +bool Caches::bindPixelBuffer(const GLuint buffer) {
    +    if (mCurrentPixelBuffer != buffer) {
    +        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
    +        mCurrentPixelBuffer = buffer;
    +        return true;
    +    }
    +    return false;
    +}
    +
    +bool Caches::unbindPixelBuffer() {
    +    if (mCurrentPixelBuffer) {
    +        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    +        mCurrentPixelBuffer = 0;
    +        return true;
    +    }
    +    return false;
    +}
    +
    +///////////////////////////////////////////////////////////////////////////////
     // Meshes and textures
     ///////////////////////////////////////////////////////////////////////////////
     
    
    diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
    index 63836c1..91b938b 100644
    --- a/libs/hwui/Caches.h
    +++ b/libs/hwui/Caches.h
    
    @@ -176,6 +176,16 @@
         bool unbindIndicesBuffer();
     
         /**
    +     * Binds the specified buffer as the current GL unpack pixel buffer.
    +     */
    +    bool bindPixelBuffer(const GLuint buffer);
    +
    +    /**
    +     * Resets the current unpack pixel buffer to 0 (default value.)
    +     */
    +    bool unbindPixelBuffer();
    +
    +    /**
          * Binds an attrib to the specified float vertex pointer.
          * Assumes a stride of gMeshStride and a size of 2.
          */
    @@ -307,6 +317,7 @@
     
         GLuint mCurrentBuffer;
         GLuint mCurrentIndicesBuffer;
    +    GLuint mCurrentPixelBuffer;
         void* mCurrentPositionPointer;
         GLsizei mCurrentPositionStride;
         void* mCurrentTexCoordsPointer;
    
    diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
    index 46beb94..790c4f4 100644
    --- a/libs/hwui/Debug.h
    +++ b/libs/hwui/Debug.h
    
    @@ -84,6 +84,9 @@
     // Turn on to insert an event marker for each display list op
     #define DEBUG_DISPLAY_LIST_OPS_AS_EVENTS 0
     
    +// Turn on to highlight drawing batches and merged batches with different colors
    +#define DEBUG_MERGE_BEHAVIOR 0
    +
     #if DEBUG_INIT
         #define INIT_LOGD(...) ALOGD(__VA_ARGS__)
     #else
    
    diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
    index fe51bf9..f0084f20 100644
    --- a/libs/hwui/DeferredDisplayList.cpp
    +++ b/libs/hwui/DeferredDisplayList.cpp
    
    @@ -21,7 +21,9 @@
     
     #include <utils/Trace.h>
     
    +#include "Caches.h"
     #include "Debug.h"
    +#include "DeferredDisplayList.h"
     #include "DisplayListOp.h"
     #include "OpenGLRenderer.h"
     
    @@ -37,15 +39,27 @@
     // Depth of the save stack at the beginning of batch playback at flush time
     #define FLUSH_SAVE_STACK_DEPTH 2
     
    +#define DEBUG_COLOR_BARRIER          0x1f000000
    +#define DEBUG_COLOR_MERGEDBATCH      0x5f7f7fff
    +#define DEBUG_COLOR_MERGEDBATCH_SOLO 0x5f7fff7f
    +
     /////////////////////////////////////////////////////////////////////////////////
     // Operation Batches
     /////////////////////////////////////////////////////////////////////////////////
     
    -class DrawOpBatch {
    +class Batch {
     public:
    -    DrawOpBatch() { mOps.clear(); }
    +    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) = 0;
    +    virtual ~Batch() {}
    +};
     
    -    virtual ~DrawOpBatch() { mOps.clear(); }
    +class DrawBatch : public Batch {
    +public:
    +    DrawBatch(int batchId, mergeid_t mergeId) : mBatchId(batchId), mMergeId(mergeId) {
    +        mOps.clear();
    +    }
    +
    +    virtual ~DrawBatch() { mOps.clear(); }
     
         void add(DrawOp* op) {
             // NOTE: ignore empty bounds special case, since we don't merge across those ops
    @@ -53,7 +67,7 @@
             mOps.add(op);
         }
     
    -    virtual bool intersects(Rect& rect) {
    +    bool intersects(Rect& rect) {
             if (!rect.intersects(mBounds)) return false;
     
             for (unsigned int i = 0; i < mOps.size(); i++) {
    @@ -70,8 +84,9 @@
             return false;
         }
     
    -    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
    -        DEFER_LOGD("replaying draw batch %p", this);
    +    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
    +        DEFER_LOGD("%d  replaying DrawingBatch %p, with %d ops (batch id %x, merge id %p)",
    +                index, this, mOps.size(), mOps[0]->getBatchId(), mOps[0]->getMergeId());
     
             status_t status = DrawGlInfo::kStatusDone;
             DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
    @@ -83,31 +98,127 @@
     #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
                 renderer.eventMark(op->name());
     #endif
    -            status |= op->applyDraw(renderer, dirty, 0);
    +            status |= op->applyDraw(renderer, dirty);
                 logBuffer.writeCommand(0, op->name());
    +
    +#if DEBUG_MERGE_BEHAVIOR
    +            Rect& bounds = mOps[i]->state.mBounds;
    +            int batchColor = 0x1f000000;
    +            if (getBatchId() & 0x1) batchColor |= 0x0000ff;
    +            if (getBatchId() & 0x2) batchColor |= 0x00ff00;
    +            if (getBatchId() & 0x4) batchColor |= 0xff0000;
    +            renderer.drawScreenSpaceColorRect(bounds.left, bounds.top, bounds.right, bounds.bottom,
    +                    batchColor);
    +#endif
             }
             return status;
         }
     
    +    inline int getBatchId() const { return mBatchId; }
    +    inline mergeid_t getMergeId() const { return mMergeId; }
         inline int count() const { return mOps.size(); }
    -private:
    +
    +protected:
         Vector<DrawOp*> mOps;
         Rect mBounds;
    +private:
    +    int mBatchId;
    +    mergeid_t mMergeId;
     };
     
    -class StateOpBatch : public DrawOpBatch {
    +// compare alphas approximately, with a small margin
    +#define NEQ_FALPHA(lhs, rhs) \
    +        fabs((float)lhs - (float)rhs) > 0.001f
    +
    +class MergingDrawBatch : public DrawBatch {
    +public:
    +    MergingDrawBatch(int batchId, mergeid_t mergeId) : DrawBatch(batchId, mergeId) {}
    +
    +    /*
    +     * Checks if a (mergeable) op can be merged into this batch
    +     *
    +     * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is
    +     * important to consider all paint attributes used in the draw calls in deciding both a) if an
    +     * op tries to merge at all, and b) if the op
    +     *
    +     * False positives can lead to information from the paints of subsequent merged operations being
    +     * dropped, so we make simplifying qualifications on the ops that can merge, per op type.
    +     */
    +    bool canMergeWith(DrawOp* op) {
    +        if (!op->state.mMatrix.isPureTranslate()) return false;
    +
    +        bool isTextBatch = getBatchId() == DeferredDisplayList::kOpBatch_Text ||
    +                getBatchId() == DeferredDisplayList::kOpBatch_ColorText;
    +
    +        // Overlapping other operations is only allowed for text without shadow. For other ops,
    +        // multiDraw isn't guaranteed to overdraw correctly
    +        if (!isTextBatch || op->state.mDrawModifiers.mHasShadow) {
    +            if (intersects(op->state.mBounds)) return false;
    +        }
    +
    +        const DeferredDisplayState& lhs = op->state;
    +        const DeferredDisplayState& rhs = mOps[0]->state;
    +
    +        if (NEQ_FALPHA(lhs.mAlpha, rhs.mAlpha)) return false;
    +
    +        // if paints are equal, then modifiers + paint attribs don't need to be compared
    +        if (op->mPaint == mOps[0]->mPaint) return true;
    +
    +        if (op->getPaintAlpha() != mOps[0]->getPaintAlpha()) return false;
    +
    +        /* Draw Modifiers compatibility check
    +         *
    +         * Shadows are ignored, as only text uses them, and in that case they are drawn
    +         * per-DrawTextOp, before the unified text draw. Because of this, it's always safe to merge
    +         * text UNLESS a later draw's shadow should overlays a previous draw's text. This is covered
    +         * above with the intersection check.
    +         *
    +         * OverrideLayerAlpha is also ignored, as it's only used for drawing layers, which are never
    +         * merged.
    +         *
    +         * These ignore cases prevent us from simply memcmp'ing the drawModifiers
    +         */
    +
    +        const DrawModifiers& lhsMod = lhs.mDrawModifiers;
    +        const DrawModifiers& rhsMod = rhs.mDrawModifiers;
    +        if (lhsMod.mShader != rhsMod.mShader) return false;
    +        if (lhsMod.mColorFilter != rhsMod.mColorFilter) return false;
    +
    +        // Draw filter testing expects bit fields to be clear if filter not set.
    +        if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false;
    +        if (lhsMod.mPaintFilterClearBits != rhsMod.mPaintFilterClearBits) return false;
    +        if (lhsMod.mPaintFilterSetBits != rhsMod.mPaintFilterSetBits) return false;
    +
    +        return true;
    +    }
    +
    +    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
    +        DEFER_LOGD("%d  replaying DrawingBatch %p, with %d ops (batch id %x, merge id %p)",
    +                index, this, mOps.size(), getBatchId(), getMergeId());
    +        if (mOps.size() == 1) {
    +            return DrawBatch::replay(renderer, dirty, false);
    +        }
    +
    +        DrawOp* op = mOps[0];
    +        status_t status = op->multiDraw(renderer, dirty, mOps, mBounds);
    +        DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
    +        buffer.writeCommand(0, "multiDraw");
    +        buffer.writeCommand(1, op->name());
    +
    +#if DEBUG_MERGE_BEHAVIOR
    +        renderer.drawScreenSpaceColorRect(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom,
    +                DEBUG_COLOR_MERGEDBATCH);
    +#endif
    +        return status;
    +    }
    +};
    +
    +class StateOpBatch : public Batch {
     public:
         // creates a single operation batch
         StateOpBatch(StateOp* op) : mOp(op) {}
     
    -    bool intersects(Rect& rect) {
    -        // if something checks for intersection, it's trying to go backwards across a state op,
    -        // something not currently supported - state ops are always barriers
    -        CRASH();
    -        return false;
    -    }
    -
    -    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
    +    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
             DEFER_LOGD("replaying state op batch %p", this);
             renderer.restoreDisplayState(mOp->state);
     
    @@ -123,18 +234,11 @@
         const StateOp* mOp;
     };
     
    -class RestoreToCountBatch : public DrawOpBatch {
    +class RestoreToCountBatch : public Batch {
     public:
         RestoreToCountBatch(StateOp* op, int restoreCount) : mOp(op), mRestoreCount(restoreCount) {}
     
    -    bool intersects(Rect& rect) {
    -        // if something checks for intersection, it's trying to go backwards across a state op,
    -        // something not currently supported - state ops are always barriers
    -        CRASH();
    -        return false;
    -    }
    -
    -    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
    +    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
             DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount);
     
             renderer.restoreDisplayState(mOp->state);
    @@ -154,14 +258,30 @@
         const int mRestoreCount;
     };
     
    +#if DEBUG_MERGE_BEHAVIOR
    +class BarrierDebugBatch : public Batch {
    +    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
    +        renderer.drawScreenSpaceColorRect(0, 0, 10000, 10000, DEBUG_COLOR_BARRIER);
    +        return DrawGlInfo::kStatusDrew;
    +    }
    +};
    +#endif
    +
     /////////////////////////////////////////////////////////////////////////////////
     // DeferredDisplayList
     /////////////////////////////////////////////////////////////////////////////////
     
     void DeferredDisplayList::resetBatchingState() {
         for (int i = 0; i < kOpBatch_Count; i++) {
    -        mBatchIndices[i] = -1;
    +        mBatchLookup[i] = NULL;
    +        mMergingBatches[i].clear();
         }
    +#if DEBUG_MERGE_BEHAVIOR
    +    if (mBatches.size() != 0) {
    +        mBatches.add(new BarrierDebugBatch());
    +    }
    +#endif
    +    mEarliestBatchIndex = mBatches.size();
     }
     
     void DeferredDisplayList::clear() {
    @@ -173,6 +293,7 @@
         }
         mBatches.clear();
         mSaveStack.clear();
    +    mEarliestBatchIndex = 0;
     }
     
     /////////////////////////////////////////////////////////////////////////////////
    @@ -281,28 +402,35 @@
             return; // quick rejected
         }
     
    -    op->onDrawOpDeferred(renderer);
    +    int batchId = kOpBatch_None;
    +    mergeid_t mergeId = (mergeid_t) -1;
    +    bool mergeable = op->onDefer(renderer, &batchId, &mergeId);
    +
    +    // complex clip has a complex set of expectations on the renderer state - for now, avoid taking
    +    // the merge path in those cases
    +    mergeable &= !recordingComplexClip();
     
         if (CC_UNLIKELY(renderer.getCaches().drawReorderDisabled)) {
             // TODO: elegant way to reuse batches?
    -        DrawOpBatch* b = new DrawOpBatch();
    +        DrawBatch* b = new DrawBatch(batchId, mergeId);
             b->add(op);
             mBatches.add(b);
             return;
         }
     
    -    // disallowReorder isn't set, so find the latest batch of the new op's type, and try to merge
    -    // the new op into it
    -    DrawOpBatch* targetBatch = NULL;
    -    int batchId = op->getBatchId();
    +    // find the latest batch of the new op's type, and try to merge the new op into it
    +    DrawBatch* targetBatch = NULL;
     
    +    // insertion point of a new batch, will hopefully be immediately after similar batch
    +    // (eventually, should be similar shader)
    +    int insertBatchIndex = mBatches.size();
         if (!mBatches.isEmpty()) {
             if (op->state.mBounds.isEmpty()) {
                 // don't know the bounds for op, so add to last batch and start from scratch on next op
    -            mBatches.top()->add(op);
    -            for (int i = 0; i < kOpBatch_Count; i++) {
    -                mBatchIndices[i] = -1;
    -            }
    +            DrawBatch* b = new DrawBatch(batchId, mergeId);
    +            b->add(op);
    +            mBatches.add(b);
    +            resetBatchingState();
     #if DEBUG_DEFER
                 DEFER_LOGD("Warning: Encountered op with empty bounds, resetting batches");
                 op->output(2);
    @@ -310,13 +438,36 @@
                 return;
             }
     
    -        if (batchId >= 0 && mBatchIndices[batchId] != -1) {
    -            int targetIndex = mBatchIndices[batchId];
    -            targetBatch = mBatches[targetIndex];
    +        if (mergeable) {
    +            // Try to merge with any existing batch with same mergeId.
    +            if (mMergingBatches[batchId].get(mergeId, targetBatch)) {
    +                if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op)) {
    +                    targetBatch = NULL;
    +                }
    +            }
    +        } else {
    +            // join with similar, non-merging batch
    +            targetBatch = (DrawBatch*)mBatchLookup[batchId];
    +        }
    +
    +        if (targetBatch || mergeable) {
                 // iterate back toward target to see if anything drawn since should overlap the new op
    -            for (int i = mBatches.size() - 1; i > targetIndex; i--) {
    -                DrawOpBatch* overBatch = mBatches[i];
    +            // if no target, merging ops still interate to find similar batch to insert after
    +            for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) {
    +                DrawBatch* overBatch = (DrawBatch*)mBatches[i];
    +
    +                if (overBatch == targetBatch) break;
    +
    +                // TODO: also consider shader shared between batch types
    +                if (batchId == overBatch->getBatchId()) {
    +                    insertBatchIndex = i + 1;
    +                    if (!targetBatch) break; // found insert position, quit
    +                }
    +
                     if (overBatch->intersects(op->state.mBounds)) {
    +                    // NOTE: it may be possible to optimize for special cases where two operations
    +                    // of the same batch/paint could swap order, such as with a non-mergeable
    +                    // (clipped) and a mergeable text operation
                         targetBatch = NULL;
     #if DEBUG_DEFER
                         DEFER_LOGD("op couldn't join batch %d, was intersected by batch %d",
    @@ -328,13 +479,21 @@
                 }
             }
         }
    +
         if (!targetBatch) {
    -        targetBatch = new DrawOpBatch();
    -        mBatches.add(targetBatch);
    -        if (batchId >= 0) {
    -            mBatchIndices[batchId] = mBatches.size() - 1;
    +        if (mergeable) {
    +            targetBatch = new MergingDrawBatch(batchId, mergeId);
    +            mMergingBatches[batchId].put(mergeId, targetBatch);
    +        } else {
    +            targetBatch = new DrawBatch(batchId, mergeId);
    +            mBatchLookup[batchId] = targetBatch;
    +            DEFER_LOGD("creating Batch %p, bid %x, at %d",
    +                    targetBatch, batchId, insertBatchIndex);
             }
    +
    +        mBatches.insertAt(targetBatch, insertBatchIndex);
         }
    +
         targetBatch->add(op);
     }
     
    @@ -362,21 +521,21 @@
     // Replay / flush
     /////////////////////////////////////////////////////////////////////////////////
     
    -static status_t replayBatchList(Vector<DrawOpBatch*>& batchList,
    +static status_t replayBatchList(const Vector<Batch*>& batchList,
             OpenGLRenderer& renderer, Rect& dirty) {
         status_t status = DrawGlInfo::kStatusDone;
     
    -    int opCount = 0;
         for (unsigned int i = 0; i < batchList.size(); i++) {
    -        status |= batchList[i]->replay(renderer, dirty);
    -        opCount += batchList[i]->count();
    +        status |= batchList[i]->replay(renderer, dirty, i);
         }
    -    DEFER_LOGD("--flushed, drew %d batches (total %d ops)", batchList.size(), opCount);
    +    DEFER_LOGD("--flushed, drew %d batches", batchList.size());
         return status;
     }
     
     status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
         ATRACE_NAME("flush drawing commands");
    +    Caches::getInstance().fontRenderer->endPrecaching();
    +
         status_t status = DrawGlInfo::kStatusDone;
     
         if (isEmpty()) return status; // nothing to flush
    @@ -397,7 +556,6 @@
         renderer.setDrawModifiers(restoreDrawModifiers);
     
         DEFER_LOGD("--flush complete, returning %x", status);
    -
         clear();
         return status;
     }
    
    diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
    index 653f315..9782c1c 100644
    --- a/libs/hwui/DeferredDisplayList.h
    +++ b/libs/hwui/DeferredDisplayList.h
    
    @@ -22,6 +22,9 @@
     
     #include "Matrix.h"
     #include "Rect.h"
    +#include "utils/TinyHashMap.h"
    +
    +class SkBitmap;
     
     namespace android {
     namespace uirenderer {
    @@ -31,16 +34,21 @@
     class SaveOp;
     class SaveLayerOp;
     class StateOp;
    -class DrawOpBatch;
     class OpenGLRenderer;
     
    +class Batch;
    +class DrawBatch;
    +class MergingDrawBatch;
    +
    +typedef void* mergeid_t;
    +
     class DeferredDisplayList {
     public:
         DeferredDisplayList() { clear(); }
         ~DeferredDisplayList() { clear(); }
     
         enum OpBatchId {
    -        kOpBatch_None = -1, // Don't batch
    +        kOpBatch_None = 0, // Don't batch
             kOpBatch_Bitmap,
             kOpBatch_Patch,
             kOpBatch_AlphaVertices,
    @@ -96,8 +104,20 @@
         Vector<int> mSaveStack;
         int mComplexClipStackStart;
     
    -    Vector<DrawOpBatch*> mBatches;
    -    int mBatchIndices[kOpBatch_Count];
    +    Vector<Batch*> mBatches;
    +
    +    // Maps batch ids to the most recent *non-merging* batch of that id
    +    Batch* mBatchLookup[kOpBatch_Count];
    +
    +    // Points to the index after the most recent barrier
    +    int mEarliestBatchIndex;
    +
    +    /**
    +     * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen
    +     * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not
    +     * collide, which avoids the need to resolve mergeid collisions.
    +     */
    +    TinyHashMap<mergeid_t, DrawBatch*> mMergingBatches[kOpBatch_Count];
     };
     
     }; // namespace uirenderer
    
    diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
    index 36c95f9..26abec2 100644
    --- a/libs/hwui/DisplayList.cpp
    +++ b/libs/hwui/DisplayList.cpp
    
    @@ -485,7 +485,7 @@
     
     #if DEBUG_DISPLAY_LIST
         Rect* clipRect = renderer.getClipRect();
    -    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
    +    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
                 level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
                 clipRect->right, clipRect->bottom);
     #endif
    
    diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
    index a5dee9f..ad7edb1 100644
    --- a/libs/hwui/DisplayListOp.h
    +++ b/libs/hwui/DisplayListOp.h
    
    @@ -121,6 +121,7 @@
     };
     
     class DrawOp : public DisplayListOp {
    +friend class MergingDrawBatch;
     public:
         DrawOp(SkPaint* paint)
                 : mPaint(paint), mQuickRejected(false) {}
    @@ -145,12 +146,41 @@
                 return;
             }
     
    -        replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty, level);
    +        replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
         }
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) = 0;
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
     
    -    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
    +    /**
    +     * Draw multiple instances of an operation, must be overidden for operations that merge
    +     *
    +     * Currently guarantees certain similarities between ops (see MergingDrawBatch::canMergeWith),
    +     * and pure translation transformations. Other guarantees of similarity should be enforced by
    +     * reducing which operations are tagged as mergeable.
    +     */
    +    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
    +            const Vector<DrawOp*>& ops, const Rect& bounds) {
    +        status_t status = DrawGlInfo::kStatusDone;
    +        for (unsigned int i = 0; i < ops.size(); i++) {
    +            renderer.restoreDisplayState(ops[i]->state);
    +            status |= ops[i]->applyDraw(renderer, dirty);
    +        }
    +        return status;
    +    }
    +
    +    /*
    +     * When this method is invoked the state field is initialized to have the
    +     * final rendering state. We can thus use it to process data as it will be
    +     * used at draw time.
    +     *
    +     * Additionally, this method allows subclasses to provide defer-time preferences for batching
    +     * and merging.
    +     *
    +     * Return true if the op can merge with others of its kind (such subclasses should implement
    +     * multiDraw)
    +     */
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
    +        return false;
         }
     
         // returns true if bounds exist
    @@ -160,12 +190,11 @@
         void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
         bool getQuickRejected() { return mQuickRejected; }
     
    -    /** Batching disabled by default, turned on for individual ops */
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return DeferredDisplayList::kOpBatch_None;
    +    inline int getPaintAlpha() {
    +        return OpenGLRenderer::getAlphaDirect(mPaint);
         }
     
    -    float strokeWidthOutset() {
    +    inline float strokeWidthOutset() {
             float width = mPaint->getStrokeWidth();
             if (width == 0) return 0.5f; // account for hairline
             return width * 0.5f;
    @@ -207,6 +236,14 @@
             return true;
         }
     
    +    bool mergeAllowed() {
    +        // checks that we're unclipped, and srcover
    +        const Rect& opBounds = state.mBounds;
    +        return fabs(opBounds.getWidth() - mLocalBounds.getWidth()) < 0.1 &&
    +                fabs(opBounds.getHeight() - mLocalBounds.getHeight()) < 0.1 &&
    +                (OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode);
    +    }
    +
     protected:
         Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint
     };
    @@ -686,20 +723,58 @@
                         paint),
                 mBitmap(bitmap) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
                     getPaint(renderer));
         }
     
    +#define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \
    +    TextureVertex::set(ptr++, posRect.xDim - offsetRect.left, posRect.yDim - offsetRect.top, \
    +            texCoordsRect.xDim, texCoordsRect.yDim)
    +
    +    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
    +            const Vector<DrawOp*>& ops, const Rect& bounds) {
    +        renderer.restoreDisplayState(state, true); // restore all but the clip
    +        renderer.setFullScreenClip(); // ensure merged ops aren't clipped
    +        TextureVertex vertices[6 * ops.size()];
    +        TextureVertex* vertex = &vertices[0];
    +
    +        // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op, and allowing
    +        // them to be merged in getBatchId()
    +        const Rect texCoords(0, 0, 1, 1);
    +
    +        const float width = mBitmap->width();
    +        const float height = mBitmap->height();
    +        for (unsigned int i = 0; i < ops.size(); i++) {
    +            const Rect& opBounds = ops[i]->state.mBounds;
    +            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
    +            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
    +            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
    +
    +            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
    +            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
    +            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
    +        }
    +
    +        return renderer.drawBitmaps(mBitmap, ops.size(), &vertices[0], bounds, mPaint);
    +    }
    +
         virtual void output(int level, uint32_t logFlags) {
             OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
         }
     
         virtual const char* name() { return "DrawBitmap"; }
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return DeferredDisplayList::kOpBatch_Bitmap;
    +
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
    +        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
    +        *mergeId = (mergeid_t)mBitmap;
    +
    +        // don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
    +        // MergingDrawBatch::canMergeWith
    +        return mergeAllowed() && (mBitmap->getConfig() != SkBitmap::kA8_Config);
         }
     
    +    const SkBitmap* bitmap() { return mBitmap; }
     protected:
         SkBitmap* mBitmap;
     };
    @@ -713,7 +788,7 @@
             transform.mapRect(mLocalBounds);
         }
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
         }
     
    @@ -721,9 +796,11 @@
             OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
         }
     
    -    virtual const char* name() { return "DrawBitmap"; }
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return DeferredDisplayList::kOpBatch_Bitmap;
    +    virtual const char* name() { return "DrawBitmapMatrix"; }
    +
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
    +        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
    +        return false;
         }
     
     private:
    @@ -738,7 +815,7 @@
                 : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
                 mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
                     mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
                     getPaint(renderer));
    @@ -750,8 +827,10 @@
         }
     
         virtual const char* name() { return "DrawBitmapRect"; }
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return DeferredDisplayList::kOpBatch_Bitmap;
    +
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
    +        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
    +        return false;
         }
     
     private:
    @@ -764,7 +843,7 @@
         DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
                 : DrawBitmapOp(bitmap, left, top, paint) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
                     mLocalBounds.top, getPaint(renderer));
         }
    @@ -774,8 +853,10 @@
         }
     
         virtual const char* name() { return "DrawBitmapData"; }
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return DeferredDisplayList::kOpBatch_Bitmap;
    +
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
    +        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
    +        return false;
         }
     };
     
    @@ -787,7 +868,7 @@
                 mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
                 mVertices(vertices), mColors(colors) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
                     mVertices, mColors, getPaint(renderer));
         }
    @@ -797,8 +878,10 @@
         }
     
         virtual const char* name() { return "DrawBitmapMesh"; }
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return DeferredDisplayList::kOpBatch_Bitmap;
    +
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
    +        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
    +        return false;
         }
     
     private:
    @@ -820,7 +903,7 @@
                 mColors(colors), mxDivsCount(width), myDivsCount(height),
                 mNumColors(numColors), mAlpha(alpha), mMode(mode) {};
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             // NOTE: not calling the virtual method, which takes a paint
             return renderer.drawPatch(mBitmap, mxDivs, myDivs, mColors,
                     mxDivsCount, myDivsCount, mNumColors,
    @@ -833,8 +916,11 @@
         }
     
         virtual const char* name() { return "DrawPatch"; }
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return DeferredDisplayList::kOpBatch_Patch;
    +
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
    +        *batchId = DeferredDisplayList::kOpBatch_Patch;
    +        *mergeId = (mergeid_t)mBitmap;
    +        return true;
         }
     
     private:
    @@ -854,7 +940,7 @@
         DrawColorOp(int color, SkXfermode::Mode mode)
                 : DrawOp(0), mColor(color), mMode(mode) {};
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawColor(mColor, mMode);
         }
     
    @@ -882,13 +968,15 @@
             return true;
         }
     
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
             if (mPaint->getPathEffect()) {
    -            return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
    +            *batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
    +        } else {
    +            *batchId = mPaint->isAntiAlias() ?
    +                    DeferredDisplayList::kOpBatch_AlphaVertices :
    +                    DeferredDisplayList::kOpBatch_Vertices;
             }
    -        return mPaint->isAntiAlias() ?
    -                DeferredDisplayList::kOpBatch_AlphaVertices :
    -                DeferredDisplayList::kOpBatch_Vertices;
    +        return false;
         }
     };
     
    @@ -897,7 +985,7 @@
         DrawRectOp(float left, float top, float right, float bottom, SkPaint* paint)
                 : DrawStrokableOp(left, top, right, bottom, paint) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
                     mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
         }
    @@ -915,7 +1003,7 @@
                 : DrawBoundedOp(rects, count, paint),
                 mRects(rects), mCount(count) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawRects(mRects, mCount, getPaint(renderer));
         }
     
    @@ -925,8 +1013,9 @@
     
         virtual const char* name() { return "DrawRects"; }
     
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return DeferredDisplayList::kOpBatch_Vertices;
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
    +        *batchId = DeferredDisplayList::kOpBatch_Vertices;
    +        return false;
         }
     
     private:
    @@ -940,7 +1029,7 @@
                 float rx, float ry, SkPaint* paint)
                 : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
                     mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
         }
    @@ -962,7 +1051,7 @@
                 : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
                 mX(x), mY(y), mRadius(radius) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
         }
     
    @@ -983,7 +1072,7 @@
         DrawOvalOp(float left, float top, float right, float bottom, SkPaint* paint)
                 : DrawStrokableOp(left, top, right, bottom, paint) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
                     mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
         }
    @@ -1002,7 +1091,7 @@
                 : DrawStrokableOp(left, top, right, bottom, paint),
                 mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
                     mLocalBounds.right, mLocalBounds.bottom,
                     mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
    @@ -1033,13 +1122,16 @@
             mLocalBounds.set(left, top, left + width, top + height);
         }
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawPath(mPath, getPaint(renderer));
         }
     
    -    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
             SkPaint* paint = getPaint(renderer);
             renderer.getCaches().pathCache.precache(mPath, paint);
    +
    +        *batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
    +        return false;
         }
     
         virtual void output(int level, uint32_t logFlags) {
    @@ -1048,9 +1140,6 @@
     
         virtual const char* name() { return "DrawPath"; }
     
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
    -    }
     private:
         SkPath* mPath;
     };
    @@ -1063,7 +1152,7 @@
             mLocalBounds.outset(strokeWidthOutset());
         }
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawLines(mPoints, mCount, getPaint(renderer));
         }
     
    @@ -1073,10 +1162,11 @@
     
         virtual const char* name() { return "DrawLines"; }
     
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return mPaint->isAntiAlias() ?
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
    +        *batchId = mPaint->isAntiAlias() ?
                     DeferredDisplayList::kOpBatch_AlphaVertices :
                     DeferredDisplayList::kOpBatch_Vertices;
    +        return false;
         }
     
     protected:
    @@ -1089,7 +1179,7 @@
         DrawPointsOp(float* points, int count, SkPaint* paint)
                 : DrawLinesOp(points, count, paint) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
         }
     
    @@ -1109,17 +1199,18 @@
             OP_LOG("Draw some text, %d bytes", mBytesCount);
         }
     
    -    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
             SkPaint* paint = getPaint(renderer);
             FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
             fontRenderer.precache(paint, mText, mCount, mat4::identity());
    -    }
     
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return mPaint->getColor() == 0xff000000 ?
    +        *batchId = mPaint->getColor() == 0xff000000 ?
                     DeferredDisplayList::kOpBatch_Text :
                     DeferredDisplayList::kOpBatch_ColorText;
    +
    +        return false;
         }
    +
     protected:
         const char* mText;
         int mBytesCount;
    @@ -1135,7 +1226,7 @@
             /* TODO: inherit from DrawBounded and init mLocalBounds */
         }
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
                     mHOffset, mVOffset, getPaint(renderer));
         }
    @@ -1156,7 +1247,7 @@
             /* TODO: inherit from DrawBounded and init mLocalBounds */
         }
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
         }
     
    @@ -1189,12 +1280,7 @@
             memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
         }
     
    -    /*
    -     * When this method is invoked the state field  is initialized to have the
    -     * final rendering state. We can thus use it to process data as it will be
    -     * used at draw time.
    -     */
    -    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
    +    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
             SkPaint* paint = getPaint(renderer);
             FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
             const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
    @@ -1202,25 +1288,44 @@
                 fontRenderer.precache(paint, mText, mCount, transform);
                 mPrecacheTransform = transform;
             }
    +        *batchId = mPaint->getColor() == 0xff000000 ?
    +                DeferredDisplayList::kOpBatch_Text :
    +                DeferredDisplayList::kOpBatch_ColorText;
    +
    +        *mergeId = (mergeid_t)mPaint->getColor();
    +
    +        // don't merge decorated text - the decorations won't draw in order
    +        bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag |
    +                        SkPaint::kStrikeThruText_Flag));
    +        return mergeAllowed() && noDecorations;
         }
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
                     mPositions, getPaint(renderer), mLength);
         }
     
    +    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
    +            const Vector<DrawOp*>& ops, const Rect& bounds) {
    +        status_t status = DrawGlInfo::kStatusDone;
    +        renderer.setFullScreenClip(); // ensure merged ops aren't clipped
    +        for (unsigned int i = 0; i < ops.size(); i++) {
    +            DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
    +            renderer.restoreDisplayState(ops[i]->state, true); // restore all but the clip
    +
    +            DrawTextOp& op = *((DrawTextOp*)ops[i]);
    +            status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
    +                    op.mPositions, op.getPaint(renderer), op.mLength, drawOpMode);
    +        }
    +        return status;
    +    }
    +
         virtual void output(int level, uint32_t logFlags) {
             OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
         }
     
         virtual const char* name() { return "DrawText"; }
     
    -    virtual DeferredDisplayList::OpBatchId getBatchId() {
    -        return mPaint->getColor() == 0xff000000 ?
    -                DeferredDisplayList::kOpBatch_Text :
    -                DeferredDisplayList::kOpBatch_ColorText;
    -    }
    -
     private:
         const char* mText;
         int mBytesCount;
    @@ -1241,7 +1346,7 @@
         DrawFunctorOp(Functor* functor)
                 : DrawOp(0), mFunctor(functor) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             renderer.startMark("GL functor");
             status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
             renderer.endMark();
    @@ -1269,14 +1374,14 @@
                 mDisplayList->defer(deferStruct, level + 1);
             }
         }
    -virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
    +    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
             if (mDisplayList && mDisplayList->isRenderable()) {
                 mDisplayList->replay(replayStruct, level + 1);
             }
         }
     
         // NOT USED since replay() is overridden
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return DrawGlInfo::kStatusDone;
         }
     
    @@ -1299,7 +1404,7 @@
         DrawLayerOp(Layer* layer, float x, float y)
                 : DrawOp(0), mLayer(layer), mX(x), mY(y) {}
     
    -    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
    +    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
             return renderer.drawLayer(mLayer, mX, mY);
         }
     
    
    diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
    index 0b8f7e6a..876c38a 100644
    --- a/libs/hwui/DisplayListRenderer.cpp
    +++ b/libs/hwui/DisplayListRenderer.cpp
    
    @@ -276,6 +276,15 @@
         bitmap = refBitmap(bitmap);
         paint = refPaint(paint);
     
    +    if (srcLeft == 0 && srcTop == 0 &&
    +            srcRight == bitmap->width() && srcBottom == bitmap->height() &&
    +            (srcBottom - srcTop == dstBottom - dstTop) &&
    +            (srcRight - srcLeft == dstRight - dstLeft)) {
    +        // transform simple rect to rect drawing case into position bitmap ops, since they merge
    +        addDrawOp(new (alloc()) DrawBitmapOp(bitmap, dstLeft, dstTop, paint));
    +        return DrawGlInfo::kStatusDone;
    +    }
    +
         addDrawOp(new (alloc()) DrawBitmapRectOp(bitmap,
                         srcLeft, srcTop, srcRight, srcBottom,
                         dstLeft, dstTop, dstRight, dstBottom, paint));
    @@ -413,7 +422,9 @@
     }
     
     status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
    -        float x, float y, const float* positions, SkPaint* paint, float length) {
    +        float x, float y, const float* positions, SkPaint* paint,
    +        float length, DrawOpMode drawOpMode) {
    +
         if (!text || count <= 0) return DrawGlInfo::kStatusDone;
     
         if (length < 0.0f) length = paint->measureText(text, bytesCount);
    
    diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
    index 19f7eb6..75abad6 100644
    --- a/libs/hwui/DisplayListRenderer.h
    +++ b/libs/hwui/DisplayListRenderer.h
    
    @@ -121,8 +121,9 @@
                 float hOffset, float vOffset, SkPaint* paint);
         virtual status_t drawPosText(const char* text, int bytesCount, int count,
                 const float* positions, SkPaint* paint);
    -    virtual status_t drawText(const char* text, int bytesCount, int count,
    -            float x, float y, const float* positions, SkPaint* paint, float length);
    +    virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
    +            const float* positions, SkPaint* paint, float length, DrawOpMode drawOpMode);
    +
         virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
     
         virtual void resetShader();
    
    diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
    index 51f1e39..19b3849 100644
    --- a/libs/hwui/Dither.cpp
    +++ b/libs/hwui/Dither.cpp
    
    @@ -75,6 +75,7 @@
     void Dither::clear() {
         if (mInitialized) {
             glDeleteTextures(1, &mDitherTexture);
    +        mInitialized = false;
         }
     }
     
    
    diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
    index 44dc731..543cfa2 100644
    --- a/libs/hwui/FontRenderer.cpp
    +++ b/libs/hwui/FontRenderer.cpp
    
    @@ -33,6 +33,7 @@
     #include "Debug.h"
     #include "Extensions.h"
     #include "FontRenderer.h"
    +#include "PixelBuffer.h"
     #include "Rect.h"
     
     namespace android {
    @@ -56,7 +57,6 @@
     
         mGammaTable = NULL;
         mInitialized = false;
    -    mMaxNumberOfQuads = 1024;
     
         mCurrentCacheTexture = NULL;
     
    @@ -133,26 +133,13 @@
         for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
             mCacheTextures[i]->init();
         }
    -
    -#if DEBUG_FONT_RENDERER
    -    uint16_t totalGlyphs = 0;
    -    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
    -        totalGlyphs += mCacheTextures[i]->getGlyphCount();
    -        // Erase caches, just as a debugging facility
    -        if (mCacheTextures[i]->getTexture()) {
    -            memset(mCacheTextures[i]->getTexture(), 0,
    -                    mCacheTextures[i]->getWidth() * mCacheTextures[i]->getHeight());
    -        }
    -    }
    -    ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs);
    -#endif
     }
     
     void FontRenderer::flushLargeCaches() {
         // Start from 1; don't deallocate smallest/default texture
         for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
             CacheTexture* cacheTexture = mCacheTextures[i];
    -        if (cacheTexture->getTexture()) {
    +        if (cacheTexture->getPixelBuffer()) {
                 cacheTexture->init();
                 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
                 while (it.next()) {
    @@ -226,7 +213,7 @@
     
         uint32_t cacheWidth = cacheTexture->getWidth();
     
    -    if (!cacheTexture->getTexture()) {
    +    if (!cacheTexture->getPixelBuffer()) {
             Caches::getInstance().activeTexture(0);
             // Large-glyph texture memory is allocated only as needed
             cacheTexture->allocateTexture();
    @@ -239,7 +226,7 @@
         // or anti-aliased (8 bits per pixel)
         SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
     
    -    uint8_t* cacheBuffer = cacheTexture->getTexture();
    +    uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
         uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
     
         // Copy the glyph image, taking the mask format into account
    @@ -305,7 +292,7 @@
     }
     
     CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
    -    CacheTexture* cacheTexture = new CacheTexture(width, height, mMaxNumberOfQuads);
    +    CacheTexture* cacheTexture = new CacheTexture(width, height, gMaxNumberOfQuads);
     
         if (allocate) {
             Caches::getInstance().activeTexture(0);
    @@ -332,12 +319,12 @@
     
     // Avoid having to reallocate memory and render quad by quad
     void FontRenderer::initVertexArrayBuffers() {
    -    uint32_t numIndices = mMaxNumberOfQuads * 6;
    +    uint32_t numIndices = gMaxNumberOfQuads * 6;
         uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t);
         uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
     
         // Four verts, two triangles , six indices per quad
    -    for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) {
    +    for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
             int i6 = i * 6;
             int i4 = i * 4;
     
    @@ -377,56 +364,36 @@
         Caches& caches = Caches::getInstance();
         GLuint lastTextureId = 0;
     
    -    // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
    -    // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
    -    // With OpenGL ES 2.0 we have to upload entire stripes instead.
    -    const bool hasUnpackRowLength = Extensions::getInstance().getMajorGlVersion() >= 3;
    +    bool resetPixelStore = false;
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     
         // Iterate over all the cache textures and see which ones need to be updated
         for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
             CacheTexture* cacheTexture = mCacheTextures[i];
    -        if (cacheTexture->isDirty() && cacheTexture->getTexture()) {
    -            const Rect* dirtyRect = cacheTexture->getDirtyRect();
    -            uint32_t x = hasUnpackRowLength ? dirtyRect->left : 0;
    -            uint32_t y = dirtyRect->top;
    -            uint32_t width = cacheTexture->getWidth();
    -            uint32_t height = dirtyRect->getHeight();
    -            void* textureData = cacheTexture->getTexture() + y * width + x;
    -
    +        if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
                 if (cacheTexture->getTextureId() != lastTextureId) {
                     lastTextureId = cacheTexture->getTextureId();
                     caches.activeTexture(0);
                     glBindTexture(GL_TEXTURE_2D, lastTextureId);
    -
    -                // The unpack row length only needs to be specified when a new
    -                // texture is bound
    -                if (hasUnpackRowLength) {
    -                    glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
    -                }
                 }
     
    -            // If we can upload a sub-rectangle, use the dirty rect width
    -            // instead of the width of the entire texture
    -            if (hasUnpackRowLength) {
    -                width = dirtyRect->getWidth();
    +            if (cacheTexture->upload()) {
    +                resetPixelStore = true;
                 }
     
     #if DEBUG_FONT_RENDERER
                 ALOGD("glTexSubimage for cacheTexture %d: x, y, width height = %d, %d, %d, %d",
                         i, x, y, width, height);
     #endif
    -
    -            glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
    -                    GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
    -
    -            cacheTexture->setDirty(false);
             }
         }
     
    +    // Unbind any PBO we might have used to update textures
    +    caches.unbindPixelBuffer();
    +
         // Reset to default unpack row length to avoid affecting texture
         // uploads in other parts of the renderer
    -    if (hasUnpackRowLength) {
    +    if (resetPixelStore) {
             glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
         }
     
    @@ -539,13 +506,14 @@
             uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) {
         checkInit();
     
    +    DropShadow image;
    +    image.width = 0;
    +    image.height = 0;
    +    image.image = NULL;
    +    image.penX = 0;
    +    image.penY = 0;
    +
         if (!mCurrentFont) {
    -        DropShadow image;
    -        image.width = 0;
    -        image.height = 0;
    -        image.image = NULL;
    -        image.penX = 0;
    -        image.penY = 0;
             return image;
         }
     
    @@ -559,6 +527,11 @@
         uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
         uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
     
    +    uint32_t maxSize = Caches::getInstance().maxTextureSize;
    +    if (paddedWidth > maxSize || paddedHeight > maxSize) {
    +        return image;
    +    }
    +
         // Align buffers for renderscript usage
         if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
             paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
    @@ -578,10 +551,12 @@
             mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
                     Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
     
    +        // Unbind any PBO we might have used
    +        Caches::getInstance().unbindPixelBuffer();
    +
             blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
         }
     
    -    DropShadow image;
         image.width = paddedWidth;
         image.height = paddedHeight;
         image.image = dataBuffer;
    @@ -612,9 +587,13 @@
         font->precache(paint, text, numGlyphs);
     }
     
    +void FontRenderer::endPrecaching() {
    +    checkTextureUpdate();
    +}
    +
     bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
             uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
    -        const float* positions, Rect* bounds, Functor* functor) {
    +        const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
         if (!mCurrentFont) {
             ALOGE("No font set");
             return false;
    @@ -622,7 +601,10 @@
     
         initRender(clip, bounds, functor);
         mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
    -    finishRender();
    +
    +    if (forceFinish) {
    +        finishRender();
    +    }
     
         return mDrawn;
     }
    @@ -690,5 +672,16 @@
         *image = outImage;
     }
     
    +uint32_t FontRenderer::getCacheSize() const {
    +    uint32_t size = 0;
    +    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
    +        CacheTexture* cacheTexture = mCacheTextures[i];
    +        if (cacheTexture && cacheTexture->getPixelBuffer()) {
    +            size += cacheTexture->getPixelBuffer()->getSize();
    +        }
    +    }
    +    return size;
    +}
    +
     }; // namespace uirenderer
     }; // namespace android
    
    diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
    index 1da3b6c..307a1d9 100644
    --- a/libs/hwui/FontRenderer.h
    +++ b/libs/hwui/FontRenderer.h
    
    @@ -61,11 +61,13 @@
         void setFont(SkPaint* paint, const mat4& matrix);
     
         void precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix);
    +    void endPrecaching();
     
         // bounds is an out parameter
         bool renderPosText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
                 uint32_t len, int numGlyphs, int x, int y, const float* positions, Rect* bounds,
    -            Functor* functor);
    +            Functor* functor, bool forceFinish = true);
    +
         // bounds is an out parameter
         bool renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
                 uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds);
    @@ -95,20 +97,13 @@
             mLinearFiltering = linearFiltering;
         }
     
    -    uint32_t getCacheSize() const {
    -        uint32_t size = 0;
    -        for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
    -            CacheTexture* cacheTexture = mCacheTextures[i];
    -            if (cacheTexture && cacheTexture->getTexture()) {
    -                size += cacheTexture->getWidth() * cacheTexture->getHeight();
    -            }
    -        }
    -        return size;
    -    }
    +    uint32_t getCacheSize() const;
     
     private:
         friend class Font;
     
    +    static const uint32_t gMaxNumberOfQuads = 2048;
    +
         const uint8_t* mGammaTable;
     
         void allocateTextureMemory(CacheTexture* cacheTexture);
    @@ -162,7 +157,6 @@
     
         bool mUploadTexture;
     
    -    uint32_t mMaxNumberOfQuads;
         uint32_t mIndexBufferID;
     
         Functor* mFunctor;
    
    diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
    index bd0a4b3..06d2aad 100644
    --- a/libs/hwui/GammaFontRenderer.cpp
    +++ b/libs/hwui/GammaFontRenderer.cpp
    
    @@ -129,6 +129,12 @@
         }
     }
     
    +void ShaderGammaFontRenderer::endPrecaching() {
    +    if (mRenderer) {
    +        mRenderer->endPrecaching();
    +    }
    +}
    +
     ///////////////////////////////////////////////////////////////////////////////
     // Lookup-based renderer
     ///////////////////////////////////////////////////////////////////////////////
    @@ -146,6 +152,12 @@
         mRenderer = NULL;
     }
     
    +void LookupGammaFontRenderer::endPrecaching() {
    +    if (mRenderer) {
    +        mRenderer->endPrecaching();
    +    }
    +}
    +
     ///////////////////////////////////////////////////////////////////////////////
     // Lookup-based renderer, using 3 different correction tables
     ///////////////////////////////////////////////////////////////////////////////
    @@ -177,6 +189,14 @@
         }
     }
     
    +void Lookup3GammaFontRenderer::endPrecaching() {
    +    for (int i = 0; i < kGammaCount; i++) {
    +        if (mRenderers[i]) {
    +            mRenderers[i]->endPrecaching();
    +        }
    +    }
    +}
    +
     void Lookup3GammaFontRenderer::clear() {
         for (int i = 0; i < kGammaCount; i++) {
             delete mRenderers[i];
    
    diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
    index 5c1860e..bbfa66d 100644
    --- a/libs/hwui/GammaFontRenderer.h
    +++ b/libs/hwui/GammaFontRenderer.h
    
    @@ -40,6 +40,8 @@
         virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0;
         virtual void setupProgram(ProgramDescription& description, Program* program) const = 0;
     
    +    virtual void endPrecaching() = 0;
    +
         static GammaFontRenderer* createRenderer();
     
     protected:
    @@ -86,6 +88,8 @@
         void describe(ProgramDescription& description, const SkPaint* paint) const;
         void setupProgram(ProgramDescription& description, Program* program) const;
     
    +    void endPrecaching();
    +
     private:
         ShaderGammaFontRenderer(bool multiGamma);
     
    @@ -134,6 +138,8 @@
         void setupProgram(ProgramDescription& description, Program* program) const {
         }
     
    +    void endPrecaching();
    +
     private:
         LookupGammaFontRenderer();
     
    @@ -171,6 +177,8 @@
         void setupProgram(ProgramDescription& description, Program* program) const {
         }
     
    +    void endPrecaching();
    +
     private:
         Lookup3GammaFontRenderer();
     
    
    diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
    index eef366c..507ed95 100644
    --- a/libs/hwui/GradientCache.cpp
    +++ b/libs/hwui/GradientCache.cpp
    
    @@ -148,8 +148,11 @@
             GradientInfo& info) {
         uint32_t width = 256 * (count - 1);
     
    -    if (!mHasNpot) {
    -        width = 1 << (31 - __builtin_clz(width));
    +    // If the npot extension is not supported we cannot use non-clamp
    +    // wrap modes. We therefore find the nearest largest power of 2
    +    // unless width is already a power of 2
    +    if (!mHasNpot && (width & (width - 1)) != 0) {
    +        width = 1 << (32 - __builtin_clz(width));
         }
     
         bool hasAlpha = false;
    
    diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
    index e18d922..f81b4ff 100644
    --- a/libs/hwui/OpenGLRenderer.cpp
    +++ b/libs/hwui/OpenGLRenderer.cpp
    
    @@ -112,11 +112,9 @@
     
     OpenGLRenderer::OpenGLRenderer():
             mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) {
    -    mDrawModifiers.mShader = NULL;
    -    mDrawModifiers.mColorFilter = NULL;
    +    // *set* draw modifiers to be 0
    +    memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
         mDrawModifiers.mOverrideLayerAlpha = 1.0f;
    -    mDrawModifiers.mHasShadow = false;
    -    mDrawModifiers.mHasDrawFilter = false;
     
         memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
     
    @@ -1330,10 +1328,9 @@
             }
         }
     
    -    if (stateDeferFlags & kStateDeferFlag_Clip) {
    +    state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
    +    if (state.mClipValid) {
             state.mClip.set(currentClip);
    -    } else {
    -        state.mClip.setEmpty();
         }
     
         // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
    @@ -1344,17 +1341,22 @@
         return false;
     }
     
    -void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state) {
    +void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
         currentTransform().load(state.mMatrix);
         mDrawModifiers = state.mDrawModifiers;
         mSnapshot->alpha = state.mAlpha;
     
    -    if (!state.mClip.isEmpty()) {
    +    if (state.mClipValid && !skipClipRestore) {
             mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
             dirtyClip();
         }
     }
     
    +void OpenGLRenderer::setFullScreenClip() {
    +    mSnapshot->setClip(0, 0, mWidth, mHeight);
    +    dirtyClip();
    +}
    +
     ///////////////////////////////////////////////////////////////////////////////
     // Transforms
     ///////////////////////////////////////////////////////////////////////////////
    @@ -1963,6 +1965,42 @@
                 (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
     }
     
    +status_t OpenGLRenderer::drawBitmaps(SkBitmap* bitmap, int bitmapCount, TextureVertex* vertices,
    +        const Rect& bounds, SkPaint* paint) {
    +
    +    // merged draw operations don't need scissor, but clip should still be valid
    +    mCaches.setScissorEnabled(mScissorOptimizationDisabled);
    +
    +    mCaches.activeTexture(0);
    +    Texture* texture = mCaches.textureCache.get(bitmap);
    +    if (!texture) return DrawGlInfo::kStatusDone;
    +    const AutoTexture autoCleanup(texture);
    +
    +    int alpha;
    +    SkXfermode::Mode mode;
    +    getAlphaAndMode(paint, &alpha, &mode);
    +
    +    texture->setWrap(GL_CLAMP_TO_EDGE, true);
    +    texture->setFilter(GL_NEAREST, true); // merged ops are always pure-translation for now
    +
    +    const float x = (int) floorf(bounds.left + 0.5f);
    +    const float y = (int) floorf(bounds.top + 0.5f);
    +    if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
    +        int color = paint != NULL ? paint->getColor() : 0;
    +        drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
    +                texture->id, paint != NULL, color, alpha, mode,
    +                &vertices[0].position[0], &vertices[0].texture[0],
    +                GL_TRIANGLES, bitmapCount * 6, true, true);
    +    } else {
    +        drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
    +                texture->id, alpha / 255.0f, mode, texture->blend,
    +                &vertices[0].position[0], &vertices[0].texture[0],
    +                GL_TRIANGLES, bitmapCount * 6, false, true, 0, true);
    +    }
    +
    +    return DrawGlInfo::kStatusDrew;
    +}
    +
     status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
         const float right = left + bitmap->width();
         const float bottom = top + bitmap->height();
    @@ -2644,6 +2682,9 @@
         mCaches.dropShadowCache.setFontRenderer(fontRenderer);
         const ShadowTexture* shadow = mCaches.dropShadowCache.get(
                 paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
    +    // If the drop shadow exceeds the max texture size or couldn't be
    +    // allocated, skip drawing
    +    if (!shadow) return;
         const AutoTexture autoCleanup(shadow);
     
         const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
    @@ -2793,8 +2834,11 @@
     }
     
     status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
    -        float x, float y, const float* positions, SkPaint* paint, float length) {
    -    if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
    +        float x, float y, const float* positions, SkPaint* paint, float length,
    +        DrawOpMode drawOpMode) {
    +
    +    if (drawOpMode == kDrawOpMode_Immediate &&
    +            (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint))) {
             return DrawGlInfo::kStatusDone;
         }
     
    @@ -2812,8 +2856,13 @@
     
         SkPaint::FontMetrics metrics;
         paint->getFontMetrics(&metrics, 0.0f);
    -    if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
    -        return DrawGlInfo::kStatusDone;
    +    if (drawOpMode == kDrawOpMode_Immediate) {
    +        if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
    +            return DrawGlInfo::kStatusDone;
    +        }
    +    } else {
    +        // merged draw operations don't need scissor, but clip should still be valid
    +        mCaches.setScissorEnabled(mScissorOptimizationDisabled);
         }
     
         const float oldX = x;
    @@ -2865,17 +2914,20 @@
     
         bool status;
         TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
    +
    +    // don't call issuedrawcommand, do it at end of batch
    +    bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
         if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
             SkPaint paintCopy(*paint);
             paintCopy.setTextAlign(SkPaint::kLeft_Align);
             status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
    -                positions, hasActiveLayer ? &bounds : NULL, &functor);
    +                positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish);
         } else {
             status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
    -                positions, hasActiveLayer ? &bounds : NULL, &functor);
    +                positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish);
         }
     
    -    if (status && hasActiveLayer) {
    +    if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
             if (!pureTranslate) {
                 transform.mapRect(bounds);
             }
    @@ -3090,7 +3142,11 @@
     ///////////////////////////////////////////////////////////////////////////////
     
     void OpenGLRenderer::resetPaintFilter() {
    +    // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
    +    // comparison, see MergingDrawBatch::canMergeWith
         mDrawModifiers.mHasDrawFilter = false;
    +    mDrawModifiers.mPaintFilterClearBits = 0;
    +    mDrawModifiers.mPaintFilterSetBits = 0;
     }
     
     void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
    @@ -3362,7 +3418,7 @@
     void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
             GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
    -        bool ignoreTransform, bool dirty) {
    +        bool ignoreTransform, bool ignoreScale, bool dirty) {
     
         setupDraw();
         setupDrawWithTexture(true);
    @@ -3374,7 +3430,11 @@
         setupDrawBlending(true, mode);
         setupDrawProgram();
         if (!dirty) setupDrawDirtyRegionsDisabled();
    -    setupDrawModelView(left, top, right, bottom, ignoreTransform);
    +    if (!ignoreScale) {
    +        setupDrawModelView(left, top, right, bottom, ignoreTransform);
    +    } else {
    +        setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
    +    }
         setupDrawTexture(texture);
         setupDrawPureColorUniforms();
         setupDrawColorFilterUniforms();
    
    diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
    index dd7a5a2..a0ad888 100644
    --- a/libs/hwui/OpenGLRenderer.h
    +++ b/libs/hwui/OpenGLRenderer.h
    
    @@ -71,10 +71,17 @@
         kStateDeferFlag_Clip = 0x2
     };
     
    +enum DrawOpMode {
    +    kDrawOpMode_Immediate,
    +    kDrawOpMode_Defer,
    +    kDrawOpMode_Flush
    +};
    +
     struct DeferredDisplayState {
    -    Rect mBounds; // local bounds, mapped with matrix to be in screen space coordinates, clipped.
    +    Rect mBounds; // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped.
     
         // the below are set and used by the OpenGLRenderer at record and deferred playback
    +    bool mClipValid;
         Rect mClip;
         mat4 mMatrix;
         DrawModifiers mDrawModifiers;
    @@ -232,6 +239,8 @@
         virtual void outputDisplayList(DisplayList* displayList);
         virtual status_t drawLayer(Layer* layer, float x, float y);
         virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
    +    status_t drawBitmaps(SkBitmap* bitmap, int bitmapCount, TextureVertex* vertices,
    +            const Rect& bounds, SkPaint* paint);
         virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
         virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
                 float srcRight, float srcBottom, float dstLeft, float dstTop,
    @@ -261,7 +270,8 @@
         virtual status_t drawPosText(const char* text, int bytesCount, int count,
                 const float* positions, SkPaint* paint);
         virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
    -            const float* positions, SkPaint* paint, float length = -1.0f);
    +            const float* positions, SkPaint* paint, float length = -1.0f,
    +            DrawOpMode drawOpMode = kDrawOpMode_Immediate);
         virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
     
         virtual void resetShader();
    @@ -282,7 +292,8 @@
         SkPaint* filterPaint(SkPaint* paint);
     
         bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags);
    -    void restoreDisplayState(const DeferredDisplayState& state);
    +    void restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore = false);
    +    void setFullScreenClip();
     
         const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
         void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
    @@ -336,20 +347,18 @@
          * @param mode Where to store the resulting xfermode
          */
         static inline void getAlphaAndModeDirect(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
    -        if (paint) {
    -            *mode = getXfermode(paint->getXfermode());
    +        *mode = getXfermodeDirect(paint);
    +        *alpha = getAlphaDirect(paint);
    +    }
     
    -            // Skia draws using the color's alpha channel if < 255
    -            // Otherwise, it uses the paint's alpha
    -            int color = paint->getColor();
    -            *alpha = (color >> 24) & 0xFF;
    -            if (*alpha == 255) {
    -                *alpha = paint->getAlpha();
    -            }
    -        } else {
    -            *mode = SkXfermode::kSrcOver_Mode;
    -            *alpha = 255;
    -        }
    +    static inline SkXfermode::Mode getXfermodeDirect(SkPaint* paint) {
    +        if (!paint) return SkXfermode::kSrcOver_Mode;
    +        return getXfermode(paint->getXfermode());
    +    }
    +
    +    static inline int getAlphaDirect(SkPaint* paint) {
    +        if (!paint) return 255;
    +        return paint->getAlpha();
         }
     
         /**
    @@ -358,6 +367,20 @@
          */
         mat4 findBestFontTransform(const mat4& transform) const;
     
    +#if DEBUG_MERGE_BEHAVIOR
    +    void drawScreenSpaceColorRect(float left, float top, float right, float bottom, int color) {
    +        mCaches.setScissorEnabled(false);
    +
    +        // should only be called outside of other draw ops, so stencil can only be in test state
    +        bool stencilWasEnabled = mCaches.stencil.isTestEnabled();
    +        mCaches.stencil.disable();
    +
    +        drawColorRect(left, top, right, bottom, color, SkXfermode::kSrcOver_Mode, true);
    +
    +        if (stencilWasEnabled) mCaches.stencil.enableTest();
    +    }
    +#endif
    +
     protected:
         /**
          * Computes the projection matrix, initialize the first snapshot
    @@ -778,7 +801,7 @@
         void drawAlpha8TextureMesh(float left, float top, float right, float bottom,
                 GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
                 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
    -            bool ignoreTransform, bool dirty = true);
    +            bool ignoreTransform, bool ignoreScale = false, bool dirty = true);
     
         /**
          * Draws text underline and strike-through if needed.
    
    diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
    new file mode 100644
    index 0000000..8280370
    --- /dev/null
    +++ b/libs/hwui/PixelBuffer.cpp
    
    @@ -0,0 +1,163 @@
    +/*
    + * Copyright (C) 2013 The Android Open Source Project
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + *      http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +
    +#define LOG_TAG "OpenGLRenderer"
    +
    +#include <utils/Log.h>
    +
    +#include "Caches.h"
    +#include "Extensions.h"
    +#include "PixelBuffer.h"
    +#include "Properties.h"
    +
    +namespace android {
    +namespace uirenderer {
    +
    +///////////////////////////////////////////////////////////////////////////////
    +// CPU pixel buffer
    +///////////////////////////////////////////////////////////////////////////////
    +
    +class CpuPixelBuffer: public PixelBuffer {
    +public:
    +    CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
    +    ~CpuPixelBuffer();
    +
    +    uint8_t* map(AccessMode mode = kAccessMode_ReadWrite);
    +    void unmap();
    +
    +    uint8_t* getMappedPointer() const;
    +
    +    void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset);
    +
    +private:
    +    uint8_t* mBuffer;
    +};
    +
    +CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height):
    +        PixelBuffer(format, width, height) {
    +    mBuffer = new uint8_t[width * height * formatSize(format)];
    +}
    +
    +CpuPixelBuffer::~CpuPixelBuffer() {
    +    delete[] mBuffer;
    +}
    +
    +uint8_t* CpuPixelBuffer::map(AccessMode mode) {
    +    if (mAccessMode == kAccessMode_None) {
    +        mAccessMode = mode;
    +    }
    +    return mBuffer;
    +}
    +
    +void CpuPixelBuffer::unmap() {
    +    mAccessMode = kAccessMode_None;
    +}
    +
    +uint8_t* CpuPixelBuffer::getMappedPointer() const {
    +    return mAccessMode == kAccessMode_None ? NULL : mBuffer;
    +}
    +
    +void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
    +    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
    +            mFormat, GL_UNSIGNED_BYTE, mBuffer + offset);
    +}
    +
    +///////////////////////////////////////////////////////////////////////////////
    +// GPU pixel buffer
    +///////////////////////////////////////////////////////////////////////////////
    +
    +class GpuPixelBuffer: public PixelBuffer {
    +public:
    +    GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
    +    ~GpuPixelBuffer();
    +
    +    uint8_t* map(AccessMode mode = kAccessMode_ReadWrite);
    +    void unmap();
    +
    +    uint8_t* getMappedPointer() const;
    +
    +    void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset);
    +
    +private:
    +    GLuint mBuffer;
    +    uint8_t* mMappedPointer;
    +    Caches& mCaches;
    +};
    +
    +GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height):
    +        PixelBuffer(format, width, height), mMappedPointer(0), mCaches(Caches::getInstance()) {
    +    glGenBuffers(1, &mBuffer);
    +    mCaches.bindPixelBuffer(mBuffer);
    +    glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), NULL, GL_DYNAMIC_DRAW);
    +    mCaches.unbindPixelBuffer();
    +}
    +
    +GpuPixelBuffer::~GpuPixelBuffer() {
    +    glDeleteBuffers(1, &mBuffer);
    +}
    +
    +uint8_t* GpuPixelBuffer::map(AccessMode mode) {
    +    if (mAccessMode == kAccessMode_None) {
    +        mCaches.bindPixelBuffer(mBuffer);
    +        mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
    +        mAccessMode = mode;
    +    }
    +
    +    return mMappedPointer;
    +}
    +
    +void GpuPixelBuffer::unmap() {
    +    if (mAccessMode != kAccessMode_None) {
    +        if (mMappedPointer) {
    +            mCaches.bindPixelBuffer(mBuffer);
    +            glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
    +        }
    +        mAccessMode = kAccessMode_None;
    +        mMappedPointer = NULL;
    +    }
    +}
    +
    +uint8_t* GpuPixelBuffer::getMappedPointer() const {
    +    return mMappedPointer;
    +}
    +
    +void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
    +    // If the buffer is not mapped, unmap() will not bind it
    +    mCaches.bindPixelBuffer(mBuffer);
    +    unmap();
    +    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
    +            GL_UNSIGNED_BYTE, (void*) offset);
    +}
    +
    +///////////////////////////////////////////////////////////////////////////////
    +// Factory
    +///////////////////////////////////////////////////////////////////////////////
    +
    +PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
    +    bool gpuBuffer = type == kBufferType_Auto && Extensions::getInstance().getMajorGlVersion() >= 3;
    +    if (gpuBuffer) {
    +        char property[PROPERTY_VALUE_MAX];
    +        if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "false") > 0) {
    +            if (!strcmp(property, "true")) {
    +                return new GpuPixelBuffer(format, width, height);
    +            }
    +        }
    +    }
    +    return new CpuPixelBuffer(format, width, height);
    +}
    +
    +}; // namespace uirenderer
    +}; // namespace android
    
    diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
    new file mode 100644
    index 0000000..32d5417
    --- /dev/null
    +++ b/libs/hwui/PixelBuffer.h
    
    @@ -0,0 +1,180 @@
    +/*
    + * 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.
    + */
    +
    +#ifndef ANDROID_HWUI_PIXEL_BUFFER_H
    +#define ANDROID_HWUI_PIXEL_BUFFER_H
    +
    +#include <GLES3/gl3.h>
    +
    +namespace android {
    +namespace uirenderer {
    +
    +/**
    + * Represents a pixel buffer. A pixel buffer will be backed either by a
    + * PBO on OpenGL ES 3.0 and higher or by an array of uint8_t on other
    + * versions. If the buffer is backed by a PBO it will of type
    + * GL_PIXEL_UNPACK_BUFFER.
    + *
    + * To read from or write into a PixelBuffer you must first map the
    + * buffer using the map(AccessMode) method. This method returns a
    + * pointer to the beginning of the buffer.
    + *
    + * Before the buffer can be used by the GPU, for instance to upload
    + * a texture, you must first unmap the buffer. To do so, call the
    + * unmap() method.
    + *
    + * Mapping and unmapping a PixelBuffer can have the side effect of
    + * changing the currently active GL_PIXEL_UNPACK_BUFFER. It is
    + * therefore recommended to call Caches::unbindPixelbuffer() after
    + * using a PixelBuffer to upload to a texture.
    + */
    +class PixelBuffer {
    +public:
    +    enum BufferType {
    +        kBufferType_Auto,
    +        kBufferType_CPU
    +    };
    +
    +    enum AccessMode {
    +        kAccessMode_None = 0,
    +        kAccessMode_Read = GL_MAP_READ_BIT,
    +        kAccessMode_Write = GL_MAP_WRITE_BIT,
    +        kAccessMode_ReadWrite = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT
    +    };
    +
    +    /**
    +     * Creates a new PixelBuffer object with the specified format and
    +     * dimensions. The buffer is immediately allocated.
    +     *
    +     * The buffer type specifies how the buffer should be allocated.
    +     * By default this method will automatically choose whether to allocate
    +     * a CPU or GPU buffer.
    +     */
    +    static PixelBuffer* create(GLenum format, uint32_t width, uint32_t height,
    +            BufferType type = kBufferType_Auto);
    +
    +    virtual ~PixelBuffer() {
    +    }
    +
    +    /**
    +     * Returns the format of this render buffer.
    +     */
    +    GLenum getFormat() const {
    +        return mFormat;
    +    }
    +
    +    /**
    +     * Maps this before with the specified access mode. This method
    +     * returns a pointer to the region of memory where the buffer was
    +     * mapped.
    +     *
    +     * If the buffer is already mapped when this method is invoked,
    +     * this method will return the previously mapped pointer. The
    +     * access mode can only be changed by calling unmap() first.
    +     *
    +     * The specified access mode cannot be kAccessMode_None.
    +     */
    +    virtual uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) = 0;
    +
    +    /**
    +     * Unmaps this buffer, if needed. After the buffer is unmapped,
    +     * the pointer previously returned by map() becomes invalid and
    +     * should not be used. After calling this method, getMappedPointer()
    +     * will always return NULL.
    +     */
    +    virtual void unmap() = 0;
    +
    +    /**
    +     * Returns the current access mode for this buffer. If the buffer
    +     * is not mapped, this method returns kAccessMode_None.
    +     */
    +    AccessMode getAccessMode() const {
    +        return mAccessMode;
    +    }
    +
    +    /**
    +     * Returns the currently mapped pointer. Returns NULL if the buffer
    +     * is not mapped.
    +     */
    +    virtual uint8_t* getMappedPointer() const = 0;
    +
    +    /**
    +     * Upload the specified rectangle of this pixe buffer as a
    +     * GL_TEXTURE_2D texture. Calling this method will trigger
    +     * an unmap() if necessary.
    +     */
    +    virtual void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) = 0;
    +
    +    /**
    +     * Returns the width of the render buffer in pixels.
    +     */
    +    uint32_t getWidth() const {
    +        return mWidth;
    +    }
    +
    +    /**
    +     * Returns the height of the render buffer in pixels.
    +     */
    +    uint32_t getHeight() const {
    +        return mHeight;
    +    }
    +
    +    /**
    +     * Returns the size of this pixel buffer in bytes.
    +     */
    +    uint32_t getSize() const {
    +        return mWidth * mHeight * formatSize(mFormat);
    +    }
    +
    +    /**
    +     * Returns the number of bytes per pixel in the specified format.
    +     *
    +     * Supported formats:
    +     *      GL_ALPHA
    +     *      GL_RGBA
    +     */
    +    static uint32_t formatSize(GLenum format) {
    +        switch (format) {
    +            case GL_ALPHA:
    +                return 1;
    +            case GL_RGBA:
    +                return 4;
    +        }
    +        return 0;
    +    }
    +
    +protected:
    +    /**
    +     * Creates a new render buffer in the specified format and dimensions.
    +     * The format must be GL_ALPHA or GL_RGBA.
    +     */
    +    PixelBuffer(GLenum format, uint32_t width, uint32_t height):
    +            mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {
    +    }
    +
    +    GLenum mFormat;
    +
    +    uint32_t mWidth;
    +    uint32_t mHeight;
    +
    +    AccessMode mAccessMode;
    +
    +}; // class PixelBuffer
    +
    +}; // namespace uirenderer
    +}; // namespace android
    +
    +#endif // ANDROID_HWUI_PIXEL_BUFFER_H
    
    diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
    index e4b4f3c..6eea00c 100644
    --- a/libs/hwui/Properties.h
    +++ b/libs/hwui/Properties.h
    
    @@ -25,6 +25,10 @@
      * the OpenGLRenderer.
      */
     
    +///////////////////////////////////////////////////////////////////////////////
    +// Compile-time properties
    +///////////////////////////////////////////////////////////////////////////////
    +
     // If turned on, text is interpreted as glyphs instead of UTF-16
     #define RENDER_TEXT_AS_GLYPHS 1
     
    @@ -39,6 +43,10 @@
     // to properly implement overdraw debugging
     #define STENCIL_BUFFER_SIZE 8
     
    +///////////////////////////////////////////////////////////////////////////////
    +// Debug properties
    +///////////////////////////////////////////////////////////////////////////////
    +
     /**
      * Debug level for app developers. The value is a numeric value defined
      * by the DebugLevel enum below.
    @@ -82,6 +90,23 @@
     #define PROPERTY_DEBUG_STENCIL_CLIP "debug.hwui.show_non_rect_clip"
     
     /**
    + * Disables draw operation deferral if set to "true", forcing draw
    + * commands to be issued to OpenGL in order, and processed in sequence
    + * with state-manipulation canvas commands.
    + */
    +#define PROPERTY_DISABLE_DRAW_DEFER "debug.hwui.disable_draw_defer"
    +
    +/**
    + * Used to disable draw operation reordering when deferring draw operations
    + * Has no effect if PROPERTY_DISABLE_DRAW_DEFER is set to "true"
    + */
    +#define PROPERTY_DISABLE_DRAW_REORDER "debug.hwui.disable_draw_reorder"
    +
    +///////////////////////////////////////////////////////////////////////////////
    +// Runtime configuration properties
    +///////////////////////////////////////////////////////////////////////////////
    +
    +/**
      * Used to enable/disable scissor optimization. The accepted values are
      * "true" and "false". The default value is "false".
      *
    @@ -97,17 +122,10 @@
     #define PROPERTY_DISABLE_SCISSOR_OPTIMIZATION "ro.hwui.disable_scissor_opt"
     
     /**
    - * Disables draw operation deferral if set to "true", forcing draw
    - * commands to be issued to OpenGL in order, and processed in sequence
    - * with state-manipulation canvas commands.
    + * Indicates whether PBOs can be used to back pixel buffers.
    + * Accepted values are "true" and "false".
      */
    -#define PROPERTY_DISABLE_DRAW_DEFER "debug.hwui.disable_draw_defer"
    -
    -/**
    - * Used to disable draw operation reordering when deferring draw operations
    - * Has no effect if PROPERTY_DISABLE_DRAW_DEFER is set to "true"
    - */
    -#define PROPERTY_DISABLE_DRAW_REORDER "debug.hwui.disable_draw_reorder"
    +#define PROPERTY_ENABLE_GPU_PIXEL_BUFFERS "hwui.use_gpu_pixel_buffers"
     
     // These properties are defined in mega-bytes
     #define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
    @@ -152,8 +170,9 @@
     // Lumincance threshold above which white gamma correction is applied. Range: [0..255]
     #define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "hwui.text_gamma.white_threshold"
     
    -// Converts a number of mega-bytes into bytes
    -#define MB(s) s * 1024 * 1024
    +///////////////////////////////////////////////////////////////////////////////
    +// Default property values
    +///////////////////////////////////////////////////////////////////////////////
     
     #define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
     #define DEFAULT_LAYER_CACHE_SIZE 16.0f
    @@ -170,6 +189,13 @@
     #define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
     #define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
     
    +///////////////////////////////////////////////////////////////////////////////
    +// Misc
    +///////////////////////////////////////////////////////////////////////////////
    +
    +// Converts a number of mega-bytes into bytes
    +#define MB(s) s * 1024 * 1024
    +
     static DebugLevel readDebugLevel() {
         char property[PROPERTY_VALUE_MAX];
         if (property_get(PROPERTY_DEBUG, property, NULL) > 0) {
    
    diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
    index f1f35bd..6976eaa 100644
    --- a/libs/hwui/TextDropShadowCache.cpp
    +++ b/libs/hwui/TextDropShadowCache.cpp
    
    @@ -178,6 +178,10 @@
             FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, text, 0,
                     len, numGlyphs, radius, positions);
     
    +        if (!shadow.image) {
    +            return NULL;
    +        }
    +
             texture = new ShadowTexture;
             texture->left = shadow.penX;
             texture->top = shadow.penY;
    
    diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
    index 577f463..6c5267d 100644
    --- a/libs/hwui/font/CacheTexture.cpp
    +++ b/libs/hwui/font/CacheTexture.cpp
    
    @@ -18,6 +18,8 @@
     
     #include "CacheTexture.h"
     #include "../Debug.h"
    +#include "../Extensions.h"
    +#include "../PixelBuffer.h"
     
     namespace android {
     namespace uirenderer {
    @@ -111,6 +113,11 @@
                 mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount) {
         mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
                 mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
    +
    +    // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
    +    // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
    +    // With OpenGL ES 2.0 we have to upload entire stripes instead.
    +    mHasES3 = Extensions::getInstance().getMajorGlVersion() >= 3;
     }
     
     CacheTexture::~CacheTexture() {
    @@ -143,7 +150,7 @@
     
     void CacheTexture::releaseTexture() {
         if (mTexture) {
    -        delete[] mTexture;
    +        delete mTexture;
             mTexture = NULL;
         }
         if (mTextureId) {
    @@ -154,6 +161,17 @@
         mCurrentQuad = 0;
     }
     
    +void CacheTexture::setLinearFiltering(bool linearFiltering, bool bind) {
    +   if (linearFiltering != mLinearFiltering) {
    +       mLinearFiltering = linearFiltering;
    +
    +       const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
    +       if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId());
    +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
    +       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
    +   }
    +}
    +
     void CacheTexture::allocateMesh() {
         if (!mMesh) {
             mMesh = new TextureVertex[mMaxQuadCount * 4];
    @@ -162,7 +180,7 @@
     
     void CacheTexture::allocateTexture() {
         if (!mTexture) {
    -        mTexture = new uint8_t[mWidth * mHeight];
    +        mTexture = PixelBuffer::create(GL_ALPHA, mWidth, mHeight);
         }
     
         if (!mTextureId) {
    @@ -183,6 +201,34 @@
         }
     }
     
    +bool CacheTexture::upload() {
    +    const Rect& dirtyRect = mDirtyRect;
    +
    +    uint32_t x = mHasES3 ? dirtyRect.left : 0;
    +    uint32_t y = dirtyRect.top;
    +    uint32_t width = mHasES3 ? dirtyRect.getWidth() : mWidth;
    +    uint32_t height = dirtyRect.getHeight();
    +
    +    // The unpack row length only needs to be specified when a new
    +    // texture is bound
    +    if (mHasES3) {
    +        glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth);
    +    }
    +
    +    mTexture->upload(x, y, width, height, y * mWidth + x);
    +
    +    setDirty(false);
    +
    +    return mHasES3;
    +}
    +
    +void CacheTexture::setDirty(bool dirty) {
    +    mDirty = dirty;
    +    if (!dirty) {
    +        mDirtyRect.setEmpty();
    +    }
    +}
    +
     bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
         if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) {
             return false;
    
    diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
    index e7fb474..ddcc836 100644
    --- a/libs/hwui/font/CacheTexture.h
    +++ b/libs/hwui/font/CacheTexture.h
    
    @@ -30,6 +30,8 @@
     namespace android {
     namespace uirenderer {
     
    +class PixelBuffer;
    +
     /**
      * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
      * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
    @@ -83,6 +85,10 @@
         void allocateTexture();
         void allocateMesh();
     
    +    // Returns true if glPixelStorei(GL_UNPACK_ROW_LENGTH) must be reset
    +    // This method will also call setDirty(false)
    +    bool upload();
    +
         bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
     
         inline uint16_t getWidth() const {
    @@ -97,7 +103,7 @@
             return &mDirtyRect;
         }
     
    -    inline uint8_t* getTexture() const {
    +    inline PixelBuffer* getPixelBuffer() const {
             return mTexture;
         }
     
    @@ -110,13 +116,6 @@
             return mDirty;
         }
     
    -    inline void setDirty(bool dirty) {
    -        mDirty = dirty;
    -        if (!dirty) {
    -            mDirtyRect.setEmpty();
    -        }
    -    }
    -
         inline bool getLinearFiltering() const {
             return mLinearFiltering;
         }
    @@ -124,16 +123,7 @@
         /**
          * This method assumes that the proper texture unit is active.
          */
    -    void setLinearFiltering(bool linearFiltering, bool bind = true) {
    -        if (linearFiltering != mLinearFiltering) {
    -            mLinearFiltering = linearFiltering;
    -
    -            const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
    -            if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId());
    -            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
    -            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
    -        }
    -    }
    +    void setLinearFiltering(bool linearFiltering, bool bind = true);
     
         inline uint16_t getGlyphCount() const {
             return mNumGlyphs;
    @@ -176,7 +166,9 @@
         }
     
     private:
    -    uint8_t* mTexture;
    +    void setDirty(bool dirty);
    +
    +    PixelBuffer* mTexture;
         GLuint mTextureId;
         uint16_t mWidth;
         uint16_t mHeight;
    @@ -188,6 +180,7 @@
         uint32_t mMaxQuadCount;
         CacheBlock* mCacheBlocks;
         Rect mDirtyRect;
    +    bool mHasES3;
     };
     
     }; // namespace uirenderer
    
    diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
    index 02c1aa1..011cfc1 100644
    --- a/libs/hwui/font/Font.cpp
    +++ b/libs/hwui/font/Font.cpp
    
    @@ -25,11 +25,12 @@
     #include <SkGlyph.h>
     #include <SkUtils.h>
     
    -#include "Debug.h"
     #include "FontUtil.h"
     #include "Font.h"
    -#include "FontRenderer.h"
    -#include "Properties.h"
    +#include "../Debug.h"
    +#include "../FontRenderer.h"
    +#include "../PixelBuffer.h"
    +#include "../Properties.h"
     
     namespace android {
     namespace uirenderer {
    @@ -200,25 +201,23 @@
                 p[3].x(), p[3].y(), u1, v1, glyph->mCacheTexture);
     }
     
    -void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
    -        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
    -    int nPenX = x + glyph->mBitmapLeft;
    -    int nPenY = y + glyph->mBitmapTop;
    -
    -    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
    -    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
    +void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
    +        uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds, const float* pos) {
    +    int dstX = x + glyph->mBitmapLeft;
    +    int dstY = y + glyph->mBitmapTop;
     
         CacheTexture* cacheTexture = glyph->mCacheTexture;
    -    uint32_t cacheWidth = cacheTexture->getWidth();
    -    const uint8_t* cacheBuffer = cacheTexture->getTexture();
     
    -    uint32_t cacheX = 0, cacheY = 0;
    -    int32_t bX = 0, bY = 0;
    -    for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
    -        for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
    -            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
    -            bitmap[bY * bitmapW + bX] = tempCol;
    -        }
    +    uint32_t cacheWidth = cacheTexture->getWidth();
    +    uint32_t startY = glyph->mStartY * cacheWidth;
    +    uint32_t endY = startY + (glyph->mBitmapHeight * cacheWidth);
    +
    +    PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer();
    +    const uint8_t* cacheBuffer = pixelBuffer->map();
    +
    +    for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY;
    +            cacheY += cacheWidth, bitmapY += bitmapWidth) {
    +        memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
         }
     }
     
    
    diff --git a/libs/hwui/utils/TinyHashMap.h b/libs/hwui/utils/TinyHashMap.h
    new file mode 100644
    index 0000000..8855140
    --- /dev/null
    +++ b/libs/hwui/utils/TinyHashMap.h
    
    @@ -0,0 +1,72 @@
    +/*
    + * 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.
    + */
    +
    +#ifndef ANDROID_HWUI_TINYHASHMAP_H
    +#define ANDROID_HWUI_TINYHASHMAP_H
    +
    +#include <utils/BasicHashtable.h>
    +
    +namespace android {
    +namespace uirenderer {
    +
    +/**
    + * A very simple hash map that doesn't allow duplicate keys, overwriting the older entry.
    + *
    + * Currently, expects simple keys that are handled by hash_t()
    + */
    +template <typename TKey, typename TValue>
    +class TinyHashMap {
    +public:
    +    typedef key_value_pair_t<TKey, TValue> TEntry;
    +
    +    /**
    +     * Puts an entry in the hash, removing any existing entry with the same key
    +     */
    +    void put(TKey key, TValue value) {
    +        hash_t hash = hash_t(key);
    +
    +        ssize_t index = mTable.find(-1, hash, key);
    +        if (index != -1) {
    +            mTable.removeAt(index);
    +        }
    +
    +        TEntry initEntry(key, value);
    +        mTable.add(hash, initEntry);
    +    }
    +
    +    /**
    +     * Return true if key is in the map, in which case stores the value in the output ref
    +     */
    +    bool get(TKey key, TValue& outValue) {
    +        hash_t hash = hash_t(key);
    +        ssize_t index = mTable.find(-1, hash, key);
    +        if (index == -1) {
    +            return false;
    +        }
    +        outValue = mTable.entryAt(index).value;
    +        return true;
    +    }
    +
    +    void clear() { mTable.clear(); }
    +
    +private:
    +    BasicHashtable<TKey, TEntry> mTable;
    +};
    +
    +}; // namespace uirenderer
    +}; // namespace android
    +
    +#endif // ANDROID_HWUI_TINYHASHMAP_H
    
    diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
    index 4eb0c56..6872278 100644
    --- a/media/java/android/media/MediaDrm.java
    +++ b/media/java/android/media/MediaDrm.java
    
    @@ -215,6 +215,7 @@
     
         public static final int MEDIA_DRM_KEY_TYPE_STREAMING = 1;
         public static final int MEDIA_DRM_KEY_TYPE_OFFLINE = 2;
    +    public static final int MEDIA_DRM_KEY_TYPE_RELEASE = 3;
     
         public final class KeyRequest {
             public KeyRequest() {}
    @@ -223,28 +224,36 @@
         };
     
         /**
    -     * A key request/response exchange occurs between the app and a license
    -     * server to obtain the keys to decrypt encrypted content.  getKeyRequest()
    -     * is used to obtain an opaque key request byte array that is delivered to the
    -     * license server.  The opaque key request byte array is returned in
    -     * KeyRequest.data.  The recommended URL to deliver the key request to is
    +     * A key request/response exchange occurs between the app and a license server
    +     * to obtain or release keys used to decrypt encrypted content.
    +     * getKeyRequest() is used to obtain an opaque key request byte array that is
    +     * delivered to the license server.  The opaque key request byte array is returned
    +     * in KeyRequest.data.  The recommended URL to deliver the key request to is
          * returned in KeyRequest.defaultUrl.
          *
          * After the app has received the key request response from the server,
          * it should deliver to the response to the DRM engine plugin using the method
          * {@link #provideKeyResponse}.
          *
    -     * @param sessonId the session ID for the drm session
    +     * @param scope may be a sessionId or a keySetId, depending on the specified keyType.
    +     * When the keyType is MEDIA_DRM_KEY_TYPE_STREAMING or MEDIA_DRM_KEY_TYPE_OFFLINE,
    +     * scope should be set to the sessionId the keys will be provided to.  When the keyType
    +     * is MEDIA_DRM_KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
    +     * being released. Releasing keys from a device invalidates them for all sessions.
          * @param init container-specific data, its meaning is interpreted based on the
          * mime type provided in the mimeType parameter.  It could contain, for example,
          * the content ID, key ID or other data obtained from the content metadata that is
    -     * required in generating the key request.
    +     * required in generating the key request. init may be null when keyType is
    +     * MEDIA_DRM_KEY_TYPE_RELEASE.
          * @param mimeType identifies the mime type of the content
    -     * @param keyType specifes if the request is for streaming or offline content
    +     * @param keyType specifes the type of the request. The request may be to acquire
    +     * keys for streaming or offline content, or to release previously acquired
    +     * keys, which are identified by a keySetId.
    +
          * @param optionalParameters are included in the key request message to
          * allow a client application to provide additional message parameters to the server.
          */
    -    public native KeyRequest getKeyRequest(byte[] sessionId, byte[] init,
    +    public native KeyRequest getKeyRequest(byte[] scope, byte[] init,
                                                String mimeType, int keyType,
                                                HashMap<String, String> optionalParameters)
             throws MediaDrmException;
    @@ -272,13 +281,11 @@
             throws MediaDrmException;
     
         /**
    -     * Remove the persisted keys associated with an offline license.  Keys are persisted
    -     * when {@link provideKeyResponse} is called with keys obtained from the method
    -     * {@link getKeyRequest} using keyType = MEDIA_DRM_KEY_TYPE_OFFLINE.
    +     * Remove the current keys from a session.
          *
    -     * @param keySetId identifies the saved key set to remove
    +     * @param sessionId the session ID for the DRM session
          */
    -    public native void removeKeys(byte[] keySetId) throws MediaDrmException;
    +    public native void removeKeys(byte[] sessionId) throws MediaDrmException;
     
         /**
          * Request an informative description of the key status for the session.  The status is
    
    diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
    index 286e203..cf159f0 100644
    --- a/media/java/android/media/MediaExtractor.java
    +++ b/media/java/android/media/MediaExtractor.java
    
    @@ -67,7 +67,7 @@
          * Sets the DataSource object to be used as the data source for this extractor
          * {@hide}
          */
    -    public native final void setDataSource(DataSource source);
    +    public native final void setDataSource(DataSource source) throws IOException;
     
         /**
          * Sets the data source as a content Uri.
    @@ -121,7 +121,8 @@
          * @param path the path of the file, or the http URL
          * @param headers the headers associated with the http request for the stream you want to play
          */
    -    public final void setDataSource(String path, Map<String, String> headers) {
    +    public final void setDataSource(String path, Map<String, String> headers)
    +        throws IOException {
             String[] keys = null;
             String[] values = null;
     
    @@ -140,7 +141,7 @@
         }
     
         private native final void setDataSource(
    -            String path, String[] keys, String[] values);
    +            String path, String[] keys, String[] values) throws IOException;
     
         /**
          * Sets the data source (file-path or http URL) to use.
    @@ -154,7 +155,7 @@
          * As an alternative, the application could first open the file for reading,
          * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
          */
    -    public final void setDataSource(String path) {
    +    public final void setDataSource(String path) throws IOException {
             setDataSource(path, null, null);
         }
     
    @@ -164,7 +165,7 @@
          *
          * @param fd the FileDescriptor for the file you want to extract from.
          */
    -    public final void setDataSource(FileDescriptor fd) {
    +    public final void setDataSource(FileDescriptor fd) throws IOException {
             setDataSource(fd, 0, 0x7ffffffffffffffL);
         }
     
    @@ -178,7 +179,7 @@
          * @param length the length in bytes of the data to be extracted
          */
         public native final void setDataSource(
    -            FileDescriptor fd, long offset, long length);
    +            FileDescriptor fd, long offset, long length) throws IOException;
     
         @Override
         protected void finalize() {
    
    diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
    index 85a32ca..f745163 100644
    --- a/media/java/android/media/MediaPlayer.java
    +++ b/media/java/android/media/MediaPlayer.java
    
    @@ -1181,7 +1181,8 @@
         /**
          * Gets the duration of the file.
          *
    -     * @return the duration in milliseconds
    +     * @return the duration in milliseconds, if no duration is available
    +     *         (for example, if streaming live content), -1 is returned.
          */
         public native int getDuration();
     
    
    diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
    index 93bcf03..4a5e82e 100644
    --- a/media/java/android/media/RemoteControlClient.java
    +++ b/media/java/android/media/RemoteControlClient.java
    
    @@ -277,14 +277,12 @@
          */
         public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
         /**
    -     * @hide
    -     * TODO un-hide and add in javadoc of setTransportControlFlags(int)
          * Flag indicating a RemoteControlClient can receive changes in the media playback position
    -     * through the {@link #OnPlaybackPositionUpdateListener} interface. This flag must be set
    +     * through the {@link OnPlaybackPositionUpdateListener} interface. This flag must be set
          * in order for components that display the RemoteControlClient information, to display and
          * let the user control media playback position.
          * @see #setTransportControlFlags(int)
    -     * @see #setPlaybackPositionProvider(PlaybackPositionProvider)
    +     * @see #setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener)
          * @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
          */
         public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
    @@ -607,8 +605,6 @@
         }
     
         /**
    -     * @hide
    -     * TODO un-hide
          * Sets the current playback state and the matching media position for the current playback
          *   speed.
          * @param state The current playback state, one of the following values:
    @@ -660,7 +656,8 @@
          *      {@link #FLAG_KEY_MEDIA_PAUSE},
          *      {@link #FLAG_KEY_MEDIA_STOP},
          *      {@link #FLAG_KEY_MEDIA_FAST_FORWARD},
    -     *      {@link #FLAG_KEY_MEDIA_NEXT}
    +     *      {@link #FLAG_KEY_MEDIA_NEXT},
    +     *      {@link #FLAG_KEY_MEDIA_POSITION_UPDATE}
          */
         public void setTransportControlFlags(int transportControlFlags) {
             synchronized(mCacheLock) {
    @@ -673,8 +670,6 @@
         }
     
         /**
    -     * @hide
    -     * TODO un-hide
          * Interface definition for a callback to be invoked when the media playback position is
          * requested to be updated.
          * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
    @@ -684,7 +679,7 @@
              * Called on the implementer to notify it that the playback head should be set at the given
              * position. If the position can be changed from its current value, the implementor of
              * the interface must also update the playback position using
    -         * {@link RemoteControlClient#setPlaybackState(int, long, int)} to reflect the actual new
    +         * {@link #setPlaybackState(int, long, float)} to reflect the actual new
              * position being used, regardless of whether it differs from the requested position.
              * Failure to do so would cause the system to not know the new actual playback position,
              * and user interface components would fail to show the user where playback resumed after
    @@ -695,30 +690,26 @@
         }
     
         /**
    -     * @hide
    -     * TODO un-hide
          * Interface definition for a callback to be invoked when the media playback position is
          * queried.
          * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
          */
    -    public interface PlaybackPositionProvider {
    +    public interface OnGetPlaybackPositionListener {
             /**
              * Called on the implementer of the interface to query the current playback position.
              * @return a negative value if the current playback position (or the last valid playback
              *     position) is not known, or a zero or positive value expressed in ms indicating the
              *     current position, or the last valid known position.
              */
    -        long getPlaybackPosition();
    +        long onGetPlaybackPosition();
         }
     
         /**
    -     * @hide
    -     * TODO un-hide
          * Sets the listener to be called whenever the media playback position is requested
          * to be updated.
          * Notifications will be received in the same thread as the one in which RemoteControlClient
          * was created.
    -     * @param l
    +     * @param l the position update listener to be called
          */
         public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
             synchronized(mCacheLock) {
    @@ -737,14 +728,12 @@
         }
     
         /**
    -     * @hide
    -     * TODO un-hide
          * Sets the listener to be called whenever the media current playback position is needed.
          * Queries will be received in the same thread as the one in which RemoteControlClient
          * was created.
    -     * @param l
    +     * @param l the listener to be called to retrieve the playback position
          */
    -    public void setPlaybackPositionProvider(PlaybackPositionProvider l) {
    +    public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) {
             synchronized(mCacheLock) {
                 int oldCapa = mPlaybackPositionCapabilities;
                 if (l != null) {
    @@ -942,7 +931,7 @@
         /**
          * Provider registered by user of RemoteControlClient to provide the current playback position.
          */
    -    private PlaybackPositionProvider mPositionProvider;
    +    private OnGetPlaybackPositionListener mPositionProvider;
         /**
          * The current remote control client generation ID across the system, as known by this object
          */
    
    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 c2dc159..d98f08e 100644
    --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    
    @@ -105,7 +105,7 @@
         public static final boolean DEBUG = BaseStatusBar.DEBUG;
         public static final boolean SPEW = DEBUG;
         public static final boolean DUMPTRUCK = true; // extra dumpsys info
    -    public static final boolean DEBUG_GESTURES = true;
    +    public static final boolean DEBUG_GESTURES = false;
     
         public static final boolean DEBUG_CLINGS = false;
     
    
    diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
    index 965e378..7315aad 100644
    --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
    +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
    
    @@ -151,7 +151,9 @@
         public void onResume(int reason) {
             if (DEBUG) Log.d(TAG, "onResume()");
             mIsShowing = KeyguardUpdateMonitor.getInstance(mContext).isKeyguardVisible();
    -        maybeStartBiometricUnlock();
    +        if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
    +          maybeStartBiometricUnlock();
    +        }
             KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
     
             // Registers a callback which handles stopping the biometric unlock and restarting it in
    @@ -269,6 +271,14 @@
             }
     
             @Override
    +        public void onUserSwitchComplete(int userId) {
    +            if (DEBUG) Log.d(TAG, "onUserSwitchComplete(" + userId + ")");
    +            if (mBiometricUnlock != null) {
    +                maybeStartBiometricUnlock();
    +            }
    +        }
    +
    +        @Override
             public void onKeyguardVisibilityChanged(boolean showing) {
                 if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")");
                 boolean wasShowing = false;
    
    diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
    index ad87a4b..986dc49 100644
    --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
    +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
    
    @@ -124,6 +124,8 @@
                 mCallbacks = Lists.newArrayList();
         private ContentObserver mDeviceProvisionedObserver;
     
    +    private boolean mSwitchingUser;
    +
         private final Handler mHandler = new Handler() {
             @Override
             public void handleMessage(Message msg) {
    @@ -461,11 +463,13 @@
                             public void onUserSwitching(int newUserId, IRemoteCallback reply) {
                                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
                                         newUserId, 0, reply));
    +                            mSwitchingUser = true;
                             }
                             @Override
                             public void onUserSwitchComplete(int newUserId) throws RemoteException {
                                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
                                         newUserId));
    +                            mSwitchingUser = false;
                             }
                         });
             } catch (RemoteException e) {
    @@ -529,7 +533,6 @@
                     cb.onUserSwitching(userId);
                 }
             }
    -        setAlternateUnlockEnabled(false);
             try {
                 reply.sendResult(null);
             } catch (RemoteException e) {
    @@ -733,6 +736,10 @@
             return mKeyguardIsVisible;
         }
     
    +    public boolean isSwitchingUser() {
    +        return mSwitchingUser;
    +    }
    +
         private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
             final boolean nowPluggedIn = current.isPluggedIn();
             final boolean wasPluggedIn = old.isPluggedIn();
    
    diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
    index c49228e..08a95a6 100644
    --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
    +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
    
    @@ -319,8 +319,9 @@
                     mSwitchingUser = true;
                     resetStateLocked(null);
                     adjustStatusBarLocked();
    -                // Disable face unlock when the user switches.
    -                KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
    +                // When we switch users we want to bring the new user to the biometric unlock even
    +                // if the current user has gone to the backup.
    +                KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
                 }
             }
     
    
    diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
    index f320562..01625dd 100644
    --- a/services/java/com/android/server/ConnectivityService.java
    +++ b/services/java/com/android/server/ConnectivityService.java
    
    @@ -1470,8 +1470,7 @@
                 loge("Error modifying route - no interface name");
                 return false;
             }
    -
    -        if (r.isHostRoute() == false) {
    +        if (r.hasGateway()) {
                 RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), r.getGateway());
                 if (bestRoute != null) {
                     if (bestRoute.getGateway().equals(r.getGateway())) {
    
    diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
    index 1e1cf5a..b47e8a0 100644
    --- a/services/java/com/android/server/LocationManagerService.java
    +++ b/services/java/com/android/server/LocationManagerService.java
    
    @@ -116,6 +116,8 @@
     
         private static final int MSG_LOCATION_CHANGED = 1;
     
    +    private static final long NANOS_PER_MILLI = 1000000L;
    +
         // Location Providers may sometimes deliver location updates
         // slightly faster that requested - provide grace period so
         // we don't unnecessarily filter events that are otherwise on
    @@ -179,6 +181,11 @@
         // mapping from provider name to last known location
         private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
     
    +    // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
    +    // locations stored here are not fudged for coarse permissions.
    +    private final HashMap<String, Location> mLastLocationCoarseInterval =
    +            new HashMap<String, Location>();
    +
         // all providers that operate over proxy, for authorizing incoming location
         private final ArrayList<LocationProviderProxy> mProxyProviders =
                 new ArrayList<LocationProviderProxy>();
    @@ -423,6 +430,7 @@
             mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
             synchronized (mLock) {
                 mLastLocation.clear();
    +            mLastLocationCoarseInterval.clear();
                 for (LocationProviderInterface p : mProviders) {
                     updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
                 }
    @@ -1407,7 +1415,14 @@
     
                     if (!isAllowedByUserSettingsLocked(name, uid)) return null;
     
    -                Location location = mLastLocation.get(name);
    +                Location location;
    +                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
    +                    // Make sure that an app with coarse permissions can't get frequent location
    +                    // updates by calling LocationManager.getLastKnownLocation repeatedly.
    +                    location = mLastLocationCoarseInterval.get(name);
    +                } else {
    +                    location = mLastLocation.get(name);
    +                }
                     if (location == null) {
                         return null;
                     }
    @@ -1673,7 +1688,8 @@
     
             // Check whether sufficient time has passed
             long minTime = record.mRequest.getFastestInterval();
    -        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
    +        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
    +                / NANOS_PER_MILLI;
             if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
                 return false;
             }
    @@ -1726,13 +1742,30 @@
             }
             lastLocation.set(location);
     
    +        // Update last known coarse interval location if enough time has passed.
    +        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
    +        if (lastLocationCoarseInterval == null) {
    +            lastLocationCoarseInterval = new Location(location);
    +            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
    +        }
    +        long timeDiffNanos = location.getElapsedRealtimeNanos()
    +                - lastLocationCoarseInterval.getElapsedRealtimeNanos();
    +        if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
    +            lastLocationCoarseInterval.set(location);
    +        }
    +        // Don't ever return a coarse location that is more recent than the allowed update
    +        // interval (i.e. don't allow an app to keep registering and unregistering for
    +        // location updates to overcome the minimum interval).
    +        noGPSLocation =
    +                lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
    +
             // Skip if there are no UpdateRecords for this provider.
             ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
             if (records == null || records.size() == 0) return;
     
             // Fetch coarse location
             Location coarseLocation = null;
    -        if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
    +        if (noGPSLocation != null) {
                 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
             }
     
    @@ -2021,6 +2054,7 @@
                 addProviderLocked(provider);
                 mMockProviders.put(name, provider);
                 mLastLocation.put(name, null);
    +            mLastLocationCoarseInterval.put(name, null);
                 updateProvidersLocked();
             }
             Binder.restoreCallingIdentity(identity);
    @@ -2043,6 +2077,7 @@
                     addProviderLocked(realProvider);
                 }
                 mLastLocation.put(provider, null);
    +            mLastLocationCoarseInterval.put(provider, null);
                 updateProvidersLocked();
                 Binder.restoreCallingIdentity(identity);
             }
    @@ -2174,6 +2209,13 @@
                     pw.println("    " + provider + ": " + location);
                 }
     
    +            pw.println("  Last Known Locations Coarse Intervals:");
    +            for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
    +                String provider = entry.getKey();
    +                Location location = entry.getValue();
    +                pw.println("    " + provider + ": " + location);
    +            }
    +
                 mGeofenceManager.dump(pw);
     
                 if (mEnabledProviders.size() > 0) {
    
    diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
    index cfb892f..fa18e76 100644
    --- a/services/java/com/android/server/NotificationManagerService.java
    +++ b/services/java/com/android/server/NotificationManagerService.java
    
    @@ -43,11 +43,13 @@
     import android.content.pm.PackageManager.NameNotFoundException;
     import android.content.res.Resources;
     import android.database.ContentObserver;
    +import android.graphics.Bitmap;
     import android.media.AudioManager;
     import android.media.IAudioService;
     import android.media.IRingtonePlayer;
     import android.net.Uri;
     import android.os.Binder;
    +import android.os.Bundle;
     import android.os.Handler;
     import android.os.IBinder;
     import android.os.Message;
    @@ -81,6 +83,7 @@
     import java.io.FileNotFoundException;
     import java.io.IOException;
     import java.io.PrintWriter;
    +import java.lang.reflect.Array;
     import java.util.ArrayDeque;
     import java.util.ArrayList;
     import java.util.Arrays;
    @@ -264,18 +267,32 @@
         }
     
         private static class Archive {
    -        static final int BUFFER_SIZE = 1000;
    +        static final int BUFFER_SIZE = 250;
             ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
     
             public Archive() {
             }
     
    +        public String toString() {
    +            final StringBuilder sb = new StringBuilder();
    +            final int N = mBuffer.size();
    +            sb.append("Archive (");
    +            sb.append(N);
    +            sb.append(" notification");
    +            sb.append((N==1)?")":"s)");
    +            return sb.toString();
    +        }
    +
             public void record(StatusBarNotification nr) {
                 // Nuke heavy parts of notification before storing in archive
                 nr.notification.tickerView = null;
                 nr.notification.contentView = null;
                 nr.notification.bigContentView = null;
                 nr.notification.largeIcon = null;
    +            final Bundle extras = nr.notification.extras;
    +            extras.remove(Notification.EXTRA_LARGE_ICON);
    +            extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
    +            extras.remove(Notification.EXTRA_PICTURE);
     
                 if (mBuffer.size() == BUFFER_SIZE) {
                     mBuffer.removeFirst();
    @@ -283,6 +300,7 @@
                 mBuffer.addLast(nr);
             }
     
    +
             public void clear() {
                 mBuffer.clear();
             }
    @@ -815,22 +833,61 @@
             void dump(PrintWriter pw, String prefix, Context baseContext) {
                 final Notification notification = sbn.notification;
                 pw.println(prefix + this);
    +            pw.println(prefix + "  uid=" + sbn.uid + " userId=" + sbn.getUserId());
                 pw.println(prefix + "  icon=0x" + Integer.toHexString(notification.icon)
    -                    + " / " + idDebugString(baseContext, this.sbn.pkg, notification.icon));
    -            pw.println(prefix + "  pri=" + notification.priority);
    -            pw.println(prefix + "  score=" + this.sbn.score);
    +                    + " / " + idDebugString(baseContext, sbn.pkg, notification.icon));
    +            pw.println(prefix + "  pri=" + notification.priority + " score=" + sbn.score);
                 pw.println(prefix + "  contentIntent=" + notification.contentIntent);
                 pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);
                 pw.println(prefix + "  tickerText=" + notification.tickerText);
                 pw.println(prefix + "  contentView=" + notification.contentView);
    -            pw.println(prefix + "  uid=" + this.sbn.uid + " userId=" + this.sbn.getUserId());
    -            pw.println(prefix + "  defaults=0x" + Integer.toHexString(notification.defaults));
    -            pw.println(prefix + "  flags=0x" + Integer.toHexString(notification.flags));
    +            pw.println(prefix + String.format("  defaults=0x%08x flags=0x%08x",
    +                    notification.defaults, notification.flags));
                 pw.println(prefix + "  sound=" + notification.sound);
                 pw.println(prefix + "  vibrate=" + Arrays.toString(notification.vibrate));
    -            pw.println(prefix + "  ledARGB=0x" + Integer.toHexString(notification.ledARGB)
    -                    + " ledOnMS=" + notification.ledOnMS
    -                    + " ledOffMS=" + notification.ledOffMS);
    +            pw.println(prefix + String.format("  led=0x%08x onMs=%d offMs=%d",
    +                    notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
    +            if (notification.actions != null && notification.actions.length > 0) {
    +                pw.println(prefix + "  actions={");
    +                final int N = notification.actions.length;
    +                for (int i=0; i<N; i++) {
    +                    final Notification.Action action = notification.actions[i];
    +                    pw.println(String.format("%s    [%d] \"%s\" -> %s",
    +                            prefix,
    +                            i,
    +                            action.title,
    +                            action.actionIntent.toString()
    +                            ));
    +                }
    +                pw.println(prefix + "  }");
    +            }
    +            if (notification.extras != null && notification.extras.size() > 0) {
    +                pw.println(prefix + "  extras={");
    +                for (String key : notification.extras.keySet()) {
    +                    pw.print(prefix + "    " + key + "=");
    +                    Object val = notification.extras.get(key);
    +                    if (val == null) {
    +                        pw.println("null");
    +                    } else {
    +                        pw.print(val.toString());
    +                        if (val instanceof Bitmap) {
    +                            pw.print(String.format(" (%dx%d)",
    +                                    ((Bitmap) val).getWidth(),
    +                                    ((Bitmap) val).getHeight()));
    +                        } else if (val.getClass().isArray()) {
    +                            pw.println(" {");
    +                            final int N = Array.getLength(val);
    +                            for (int i=0; i<N; i++) {
    +                                if (i > 0) pw.println(",");
    +                                pw.print(prefix + "      " + Array.get(val, i));
    +                            }
    +                            pw.print("\n" + prefix + "    }");
    +                        }
    +                        pw.println();
    +                    }
    +                }
    +                pw.println(prefix + "  }");
    +            }
             }
     
             @Override
    @@ -2081,7 +2138,7 @@
                 if (N > 0) {
                     pw.println("  Lights List:");
                     for (int i=0; i<N; i++) {
    -                    mLights.get(i).dump(pw, "    ", mContext);
    +                    pw.println("    " + mLights.get(i));
                     }
                     pw.println("  ");
                 }
    @@ -2090,6 +2147,17 @@
                 pw.println("  mVibrateNotification=" + mVibrateNotification);
                 pw.println("  mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
                 pw.println("  mSystemReady=" + mSystemReady);
    +            pw.println("  mArchive=" + mArchive.toString());
    +            Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
    +            int i=0;
    +            while (iter.hasNext()) {
    +                pw.println("    " + iter.next());
    +                if (++i >= 5) {
    +                    if (iter.hasNext()) pw.println("    ...");
    +                    break;
    +                }
    +            }
    +
             }
         }
     }
    
    diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
    index 110c4da..128a49f 100644
    --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
    +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
    
    @@ -1817,11 +1817,13 @@
                     addServiceLocked(this, userState);
                     if (userState.mBindingServices.contains(mComponentName)) {
                         userState.mBindingServices.remove(mComponentName);
    -                    onUserStateChangedLocked(userState);
                         try {
    -                        mServiceInterface.setConnection(this, mId);
    +                       mServiceInterface.setConnection(this, mId);
    +                       onUserStateChangedLocked(userState);
                         } catch (RemoteException re) {
    -                        Slog.w(LOG_TAG, "Error while setting connection for service: " + service, re);
    +                        Slog.w(LOG_TAG, "Error while setting connection for service: "
    +                                + service, re);
    +                        binderDied();
                         }
                     } else {
                         binderDied();
    @@ -2499,7 +2501,9 @@
                 public void flush() {
                     synchronized (mLock) {
                         cancelAllPendingEventsLocked();
    -                    mSentEventsVerifier.reset();
    +                    if (mSentEventsVerifier != null) {
    +                        mSentEventsVerifier.reset();
    +                    }
                     }
                 }
     
    
    diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
    index 2417cff..bc1df85 100644
    --- a/services/java/com/android/server/am/ActivityManagerService.java
    +++ b/services/java/com/android/server/am/ActivityManagerService.java
    
    @@ -936,6 +936,12 @@
         CompatModeDialog mCompatModeDialog;
         long mLastMemUsageReportTime = 0;
     
    +    /**
    +     * Flag whether the current user is a "monkey", i.e. whether
    +     * the UI is driven by a UI automation tool.
    +     */
    +    private boolean mUserIsMonkey;
    +
         final Handler mHandler = new Handler() {
             //public Handler() {
             //    if (localLOGV) Slog.v(TAG, "Handler started!");
    @@ -7434,11 +7440,27 @@
             }
         }
     
    -    public boolean isUserAMonkey() {
    -        // For now the fact that there is a controller implies
    -        // we have a monkey.
    +    public void setUserIsMonkey(boolean userIsMonkey) {
             synchronized (this) {
    -            return mController != null;
    +            synchronized (mPidsSelfLocked) {
    +                final int callingPid = Binder.getCallingPid();
    +                ProcessRecord precessRecord = mPidsSelfLocked.get(callingPid);
    +                if (precessRecord == null) {
    +                    throw new SecurityException("Unknown process: " + callingPid);
    +                }
    +                if (precessRecord.instrumentationUiAutomationConnection  == null) {
    +                    throw new SecurityException("Only an instrumentation process "
    +                            + "with a UiAutomation can call setUserIsMonkey");
    +                }
    +            }
    +            mUserIsMonkey = userIsMonkey;
    +        }
    +    }
    +
    +    public boolean isUserAMonkey() {
    +        synchronized (this) {
    +            // If there is a controller also implies the user is a monkey.
    +            return (mUserIsMonkey || mController != null);
             }
         }
     
    @@ -12435,6 +12457,9 @@
                 } catch (RemoteException re) {
                     /* ignore */
                 }
    +            // Only a UiAutomation can set this flag and now that
    +            // it is finished we make sure it is reset to its default.
    +            mUserIsMonkey = false;
             }
             app.instrumentationWatcher = null;
             app.instrumentationUiAutomationConnection = null;
    
    diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
    index 1ebff67..8c88cab 100644
    --- a/services/java/com/android/server/location/GpsLocationProvider.java
    +++ b/services/java/com/android/server/location/GpsLocationProvider.java
    
    @@ -36,6 +36,7 @@
     import android.location.LocationListener;
     import android.location.LocationManager;
     import android.location.LocationProvider;
    +import android.location.LocationRequest;
     import android.net.ConnectivityManager;
     import android.net.NetworkInfo;
     import android.net.Uri;
    @@ -262,6 +263,9 @@
         // true if we started navigation
         private boolean mStarted;
     
    +    // true if single shot request is in progress
    +    private boolean mSingleShot;
    +
         // capabilities of the GPS engine
         private int mEngineCapabilities;
     
    @@ -382,7 +386,7 @@
     
                 if (action.equals(ALARM_WAKEUP)) {
                     if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
    -                startNavigating();
    +                startNavigating(false);
                 } else if (action.equals(ALARM_TIMEOUT)) {
                     if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
                     hibernate();
    @@ -803,10 +807,22 @@
         }
     
         private void handleSetRequest(ProviderRequest request, WorkSource source) {
    +        boolean singleShot = false;
    +
    +        // see if the request is for a single update
    +        if (request.locationRequests != null && request.locationRequests.size() > 0) {
    +            // if any request has zero or more than one updates
    +            // requested, then this is not single-shot mode
    +            singleShot = true;
    +
    +            for (LocationRequest lr : request.locationRequests) {
    +                if (lr.getNumUpdates() != 1) {
    +                    singleShot = false;
    +                }
    +            }
    +        }
    +
             if (DEBUG) Log.d(TAG, "setRequest " + request);
    -
    -
    -
             if (request.reportLocation) {
                 // update client uids
                 updateClientUids(source);
    @@ -828,7 +844,7 @@
                     }
                 } else if (!mStarted) {
                     // start GPS
    -                startNavigating();
    +                startNavigating(singleShot);
                 }
             } else {
                 updateClientUids(new WorkSource());
    @@ -982,21 +998,44 @@
             return false;
         }
     
    -    private void startNavigating() {
    +    private void startNavigating(boolean singleShot) {
             if (!mStarted) {
    -            if (DEBUG) Log.d(TAG, "startNavigating");
    +            if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
                 mTimeToFirstFix = 0;
                 mLastFixTime = 0;
                 mStarted = true;
    +            mSingleShot = singleShot;
                 mPositionMode = GPS_POSITION_MODE_STANDALONE;
     
                  if (Settings.Global.getInt(mContext.getContentResolver(),
                         Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0) {
    -                if (hasCapability(GPS_CAPABILITY_MSB)) {
    +                if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
    +                    mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
    +                } else if (hasCapability(GPS_CAPABILITY_MSB)) {
                         mPositionMode = GPS_POSITION_MODE_MS_BASED;
                     }
                 }
     
    +            if (DEBUG) {
    +                String mode;
    +
    +                switch(mPositionMode) {
    +                    case GPS_POSITION_MODE_STANDALONE:
    +                        mode = "standalone";
    +                        break;
    +                    case GPS_POSITION_MODE_MS_ASSISTED:
    +                        mode = "MS_ASSISTED";
    +                        break;
    +                    case GPS_POSITION_MODE_MS_BASED:
    +                        mode = "MS_BASED";
    +                        break;
    +                    default:
    +                        mode = "unknown";
    +                        break;
    +                }
    +                Log.d(TAG, "setting position_mode to " + mode);
    +            }
    +
                 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
                 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
                         interval, 0, 0)) {
    @@ -1028,6 +1067,7 @@
             if (DEBUG) Log.d(TAG, "stopNavigating");
             if (mStarted) {
                 mStarted = false;
    +            mSingleShot = false;
                 native_stop();
                 mTimeToFirstFix = 0;
                 mLastFixTime = 0;
    @@ -1122,6 +1162,10 @@
                 }
             }
     
    +        if (mSingleShot) {
    +            stopNavigating();
    +        }
    +
             if (mStarted && mStatus != LocationProvider.AVAILABLE) {
                 // we want to time out if we do not receive a fix
                 // within the time out and we are requesting infrequent fixes
    @@ -1283,7 +1327,8 @@
                         if (DEBUG) Log.d(TAG, "PhoneConstants.APN_REQUEST_STARTED");
                         // Nothing to do here
                     } else {
    -                    if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed");
    +                    if (DEBUG) Log.d(TAG, "startUsingNetworkFeature failed, value is " +
    +                                     result);
                         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
                         native_agps_data_conn_failed();
                     }
    
    diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
    index 154c4e8..1b8ee82 100644
    --- a/services/java/com/android/server/pm/PackageManagerService.java
    +++ b/services/java/com/android/server/pm/PackageManagerService.java
    
    @@ -8694,15 +8694,7 @@
             if (outInfo != null) {
                 // A user ID was deleted here. Go through all users and remove it
                 // from KeyStore.
    -            final int appId = outInfo.removedAppId;
    -            if (appId != -1) {
    -                final KeyStore keyStore = KeyStore.getInstance();
    -                if (keyStore != null) {
    -                    for (final int userId : sUserManager.getUserIds()) {
    -                        keyStore.clearUid(UserHandle.getUid(userId, appId));
    -                    }
    -                }
    -            }
    +            removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
             }
         }
     
    @@ -8862,6 +8854,7 @@
                     outInfo.removedUsers = new int[] {removeUser};
                 }
                 mInstaller.clearUserData(packageName, removeUser);
    +            removeKeystoreDataIfNeeded(removeUser, appId);
                 schedulePackageCleaning(packageName, removeUser, false);
                 return true;
             }
    @@ -9014,29 +9007,34 @@
             }
             PackageParser.Package p;
             boolean dataOnly = false;
    +        final int appId;
             synchronized (mPackages) {
                 p = mPackages.get(packageName);
    -            if(p == null) {
    +            if (p == null) {
                     dataOnly = true;
                     PackageSetting ps = mSettings.mPackages.get(packageName);
    -                if((ps == null) || (ps.pkg == null)) {
    -                    Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
    +                if ((ps == null) || (ps.pkg == null)) {
    +                    Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
                         return false;
                     }
                     p = ps.pkg;
                 }
    -        }
    -
    -        if (!dataOnly) {
    -            //need to check this only for fully installed applications
    -            if (p == null) {
    -                Slog.w(TAG, "Package named '" + packageName +"' doesn't exist.");
    -                return false;
    +            if (!dataOnly) {
    +                // need to check this only for fully installed applications
    +                if (p == null) {
    +                    Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
    +                    return false;
    +                }
    +                final ApplicationInfo applicationInfo = p.applicationInfo;
    +                if (applicationInfo == null) {
    +                    Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
    +                    return false;
    +                }
                 }
    -            final ApplicationInfo applicationInfo = p.applicationInfo;
    -            if (applicationInfo == null) {
    -                Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
    -                return false;
    +            if (p != null && p.applicationInfo != null) {
    +                appId = p.applicationInfo.uid;
    +            } else {
    +                appId = -1;
                 }
             }
             int retCode = mInstaller.clearUserData(packageName, userId);
    @@ -9045,9 +9043,33 @@
                         + packageName);
                 return false;
             }
    +        removeKeystoreDataIfNeeded(userId, appId);
             return true;
         }
     
    +    /**
    +     * Remove entries from the keystore daemon. Will only remove it if the
    +     * {@code appId} is valid.
    +     */
    +    private static void removeKeystoreDataIfNeeded(int userId, int appId) {
    +        if (appId < 0) {
    +            return;
    +        }
    +
    +        final KeyStore keyStore = KeyStore.getInstance();
    +        if (keyStore != null) {
    +            if (userId == UserHandle.USER_ALL) {
    +                for (final int individual : sUserManager.getUserIds()) {
    +                    keyStore.clearUid(UserHandle.getUid(individual, appId));
    +                }
    +            } else {
    +                keyStore.clearUid(UserHandle.getUid(userId, appId));
    +            }
    +        } else {
    +            Slog.w(TAG, "Could not contact keystore to clear entries for app id " + appId);
    +        }
    +    }
    +
         public void deleteApplicationCacheFiles(final String packageName,
                 final IPackageDataObserver observer) {
             mContext.enforceCallingOrSelfPermission(
    
    diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
    index 3ef9370..df90a56 100644
    --- a/services/java/com/android/server/pm/UserManagerService.java
    +++ b/services/java/com/android/server/pm/UserManagerService.java
    
    @@ -622,6 +622,8 @@
                             UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
                     writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH);
                     writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
    +                writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
    +                writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER);
                     serializer.endTag(null, TAG_RESTRICTIONS);
                 }
                 serializer.endTag(null, TAG_USER);
    @@ -742,6 +744,8 @@
                                     UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
                             readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH);
                             readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
    +                        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
    +                        readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER);
                         }
                     }
                 }
    
    diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
    index c94f7c1..9601e9a 100644
    --- a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
    +++ b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
    
    @@ -56,9 +56,9 @@
     
         private static final String UPDATE_CERTIFICATE_KEY = "config_update_certificate";
     
    -    private final File updateDir;
    -    private final File updateContent;
    -    private final File updateVersion;
    +    protected final File updateDir;
    +    protected final File updateContent;
    +    protected final File updateVersion;
     
         public ConfigUpdateInstallReceiver(String updateDir, String updateContentPath,
                                            String updateMetadataPath, String updateVersionPath) {
    @@ -222,7 +222,7 @@
             return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT));
         }
     
    -    private void writeUpdate(File dir, File file, byte[] content) throws IOException {
    +    protected void writeUpdate(File dir, File file, byte[] content) throws IOException {
             FileOutputStream out = null;
             File tmp = null;
             try {
    
    diff --git a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
    index 748849e..e8337f6 100644
    --- a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
    +++ b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
    
    @@ -18,28 +18,127 @@
     
     import android.content.Context;
     import android.content.Intent;
    +import android.os.FileUtils;
     import android.os.SELinux;
    +import android.os.SystemProperties;
     import android.provider.Settings;
     import android.util.Base64;
     import android.util.Slog;
     
    +import java.io.BufferedInputStream;
    +import java.io.File;
    +import java.io.FileInputStream;
     import java.io.IOException;
     
    +import libcore.io.ErrnoException;
    +import libcore.io.IoUtils;
    +import libcore.io.Libcore;
    +
     public class SELinuxPolicyInstallReceiver extends ConfigUpdateInstallReceiver {
     
    +    private static final String TAG = "SELinuxPolicyInstallReceiver";
    +
    +    private static final String sepolicyPath = "sepolicy";
    +    private static final String fileContextsPath = "file_contexts";
    +    private static final String propertyContextsPath = "property_contexts";
    +    private static final String seappContextsPath = "seapp_contexts";
    +
         public SELinuxPolicyInstallReceiver() {
    -        super("/data/security/", "sepolicy", "metadata/", "version");
    +        super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version");
         }
     
    -    @Override
    -    protected void install(byte[] encodedContent, int version) throws IOException {
    -        super.install(Base64.decode(encodedContent, Base64.DEFAULT), version);
    +    private void backupContexts(File contexts) {
    +        new File(contexts, seappContextsPath).renameTo(
    +                new File(contexts, seappContextsPath + "_backup"));
    +
    +        new File(contexts, propertyContextsPath).renameTo(
    +                new File(contexts, propertyContextsPath + "_backup"));
    +
    +        new File(contexts, fileContextsPath).renameTo(
    +                new File(contexts, fileContextsPath + "_backup"));
    +
    +        new File(contexts, sepolicyPath).renameTo(
    +                new File(contexts, sepolicyPath + "_backup"));
    +    }
    +
    +    private void copyUpdate(File contexts) {
    +        new File(updateDir, seappContextsPath).renameTo(new File(contexts, seappContextsPath));
    +        new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath));
    +        new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath));
    +        new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath));
    +    }
    +
    +    private int readInt(BufferedInputStream reader) throws IOException {
    +        int value = 0;
    +        for (int i=0; i < 4; i++) {
    +            value = (value << 8) | reader.read();
    +        }
    +        return value;
    +    }
    +
    +    private int[] readChunkLengths(BufferedInputStream bundle) throws IOException {
    +        int[] chunks = new int[4];
    +        chunks[0] = readInt(bundle);
    +        chunks[1] = readInt(bundle);
    +        chunks[2] = readInt(bundle);
    +        chunks[3] = readInt(bundle);
    +        return chunks;
    +    }
    +
    +    private void installFile(File destination, BufferedInputStream stream, int length)
    +            throws IOException {
    +        byte[] chunk = new byte[length];
    +        stream.read(chunk, 0, length);
    +        writeUpdate(updateDir, destination, Base64.decode(chunk, Base64.DEFAULT));
    +    }
    +
    +    private void unpackBundle() throws IOException {
    +        BufferedInputStream stream = new BufferedInputStream(new FileInputStream(updateContent));
    +        int[] chunkLengths = readChunkLengths(stream);
    +        installFile(new File(updateDir, seappContextsPath), stream, chunkLengths[0]);
    +        installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[1]);
    +        installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[2]);
    +        installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[3]);
    +    }
    +
    +    private void applyUpdate() throws IOException, ErrnoException {
    +        Slog.i(TAG, "Applying SELinux policy");
    +        File contexts = new File(updateDir.getParentFile(), "contexts");
    +        File current = new File(updateDir.getParentFile(), "current");
    +        File update = new File(updateDir.getParentFile(), "update");
    +        File tmp = new File(updateDir.getParentFile(), "tmp");
    +        if (current.exists()) {
    +            Libcore.os.symlink(updateDir.getPath(), update.getPath());
    +            Libcore.os.rename(update.getPath(), current.getPath());
    +        } else {
    +            Libcore.os.symlink(updateDir.getPath(), current.getPath());
    +        }
    +        contexts.mkdirs();
    +        backupContexts(contexts);
    +        copyUpdate(contexts);
    +        Libcore.os.symlink(contexts.getPath(), tmp.getPath());
    +        Libcore.os.rename(tmp.getPath(), current.getPath());
    +        SystemProperties.set("selinux.reload_policy", "1");
    +    }
    +
    +    private void setEnforcingMode(Context context) {
    +        boolean mode = Settings.Global.getInt(context.getContentResolver(),
    +            Settings.Global.SELINUX_STATUS, 0) == 1;
    +        SELinux.setSELinuxEnforce(mode);
         }
     
         @Override
         protected void postInstall(Context context, Intent intent) {
    -           boolean mode = Settings.Global.getInt(context.getContentResolver(),
    -                                                Settings.Global.SELINUX_STATUS, 0) == 1;
    -           SELinux.setSELinuxEnforce(mode);
    +        try {
    +            unpackBundle();
    +            applyUpdate();
    +            setEnforcingMode(context);
    +        } catch (IllegalArgumentException e) {
    +            Slog.e(TAG, "SELinux policy update malformed: ", e);
    +        } catch (IOException e) {
    +            Slog.e(TAG, "Could not update selinux policy: ", e);
    +        } catch (ErrnoException e) {
    +            Slog.e(TAG, "Could not update selinux policy: ", e);
    +        }
         }
     }
    
    diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
    index f8d5d2e..4d23e5c 100644
    --- a/services/java/com/android/server/wifi/WifiService.java
    +++ b/services/java/com/android/server/wifi/WifiService.java
    
    @@ -734,7 +734,7 @@
                     if (gateway instanceof Inet4Address) {
                         info.gateway = NetworkUtils.inetAddressToInt((Inet4Address)gateway);
                     }
    -            } else if (r.isHostRoute()) {
    +            } else if (r.hasGateway() == false) {
                     LinkAddress dest = r.getDestination();
                     if (dest.getAddress() instanceof Inet4Address) {
                         info.netmask = NetworkUtils.prefixLengthToNetmaskInt(
    
    diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
    index ca060f4..788d514 100644
    --- a/services/java/com/android/server/wm/WindowState.java
    +++ b/services/java/com/android/server/wm/WindowState.java
    
    @@ -19,6 +19,7 @@
     import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
     import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
     import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
    +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
     import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
     import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
     import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
    @@ -923,6 +924,7 @@
             return mContentChanged && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
                     && (mFrame.top != mLastFrame.top
                             || mFrame.left != mLastFrame.left)
    +                && (mAttrs.privateFlags&PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
                     && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove());
         }
     
    
    diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
    index d3d5b1b..23a4e71 100644
    --- a/wifi/java/android/net/wifi/WifiConfigStore.java
    +++ b/wifi/java/android/net/wifi/WifiConfigStore.java
    
    @@ -1111,7 +1111,8 @@
                     break setVariables;
                 }
     
    -            if (config.enterpriseConfig != null) {
    +            if (config.enterpriseConfig != null &&
    +                    config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) {
     
                     WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
     
    
    diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
    index f73a13c..4e7497c 100644
    --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
    +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
    
    @@ -19,17 +19,12 @@
     import android.os.Parcelable;
     import android.os.Process;
     import android.security.Credentials;
    +import android.security.KeyStore;
     import android.text.TextUtils;
     
    -import com.android.org.bouncycastle.asn1.ASN1InputStream;
    -import com.android.org.bouncycastle.asn1.ASN1Sequence;
    -import com.android.org.bouncycastle.asn1.DEROctetString;
    -import com.android.org.bouncycastle.asn1.x509.BasicConstraints;
    -
     import java.io.ByteArrayInputStream;
     import java.io.IOException;
     import java.security.KeyFactory;
    -import java.security.KeyStore;
     import java.security.NoSuchAlgorithmException;
     import java.security.PrivateKey;
     import java.security.cert.Certificate;
    @@ -481,7 +476,8 @@
             String caCertName = Credentials.CA_CERTIFICATE + name;
             if (mClientCertificate != null) {
                 byte[] privKeyData = mClientPrivateKey.getEncoded();
    -            ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID);
    +            ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID,
    +                            KeyStore.FLAG_ENCRYPTED);
                 if (ret == false) {
                     return ret;
                 }
    @@ -525,7 +521,7 @@
                 Certificate cert) {
             try {
                 byte[] certData = Credentials.convertToPem(cert);
    -            return keyStore.put(name, certData, Process.WIFI_UID);
    +            return keyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
             } catch (IOException e1) {
                 return false;
             } catch (CertificateException e2) {
    @@ -533,7 +529,7 @@
             }
         }
     
    -    void removeKeys(android.security.KeyStore keyStore) {
    +    void removeKeys(KeyStore keyStore) {
             String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
             // a valid client certificate is configured
             if (!TextUtils.isEmpty(client)) {
    
    diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
    index 04e7095..a5d98cc 100644
    --- a/wifi/java/android/net/wifi/WifiStateMachine.java
    +++ b/wifi/java/android/net/wifi/WifiStateMachine.java
    
    @@ -2442,6 +2442,9 @@
                             if (DBG) log("Already in delayed stop");
                             break;
                         }
    +                    /* disconnect right now, but leave the driver running for a bit */
    +                    mWifiConfigStore.disableAllNetworks();
    +
                         mInDelayedStop = true;
                         mDelayedStopCounter++;
                         if (DBG) log("Delayed stop message " + mDelayedStopCounter);
    @@ -2462,6 +2465,9 @@
                             mDelayedStopCounter++;
                             mAlarmManager.cancel(mDriverStopIntent);
                             if (DBG) log("Delayed stop ignored due to start");
    +                        if (mOperationalMode == CONNECT_MODE) {
    +                            mWifiConfigStore.enableAllNetworks();
    +                        }
                         }
                         break;
                     case CMD_DELAYED_STOP_DRIVER: