Merge "Small cleanup on InputMethodInfo"
diff --git a/api/current.txt b/api/current.txt
index 3fe602c..6c41433 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -291,6 +291,7 @@
     field public static final int autoAdvanceViewId = 16843535; // 0x101030f
     field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
     field public static final int autoLink = 16842928; // 0x10100b0
+    field public static final int autoMirrored = 16843752; // 0x10103e8
     field public static final int autoStart = 16843445; // 0x10102b5
     field public static final deprecated int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -387,6 +388,7 @@
     field public static final int cropToPadding = 16843043; // 0x1010123
     field public static final int cursorVisible = 16843090; // 0x1010152
     field public static final int customNavigationLayout = 16843474; // 0x10102d2
+    field public static final int customRoots = 16843751; // 0x10103e7
     field public static final int customTokens = 16843579; // 0x101033b
     field public static final int cycles = 16843220; // 0x10101d4
     field public static final int dashGap = 16843175; // 0x10101a7
@@ -3163,6 +3165,7 @@
     field public static final int OP_COARSE_LOCATION = 0; // 0x0
     field public static final int OP_FINE_LOCATION = 1; // 0x1
     field public static final int OP_GPS = 2; // 0x2
+    field public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42; // 0x2a
     field public static final int OP_MONITOR_LOCATION = 41; // 0x29
     field public static final int OP_NONE = -1; // 0xffffffff
   }
@@ -7624,7 +7627,7 @@
     method public void recycle();
   }
 
-  public abstract interface XmlResourceParser implements android.util.AttributeSet org.xmlpull.v1.XmlPullParser {
+  public abstract interface XmlResourceParser implements android.util.AttributeSet java.lang.AutoCloseable org.xmlpull.v1.XmlPullParser {
     method public abstract void close();
   }
 
@@ -9343,6 +9346,7 @@
     field public static final int ANTI_ALIAS_FLAG = 1; // 0x1
     field public static final int DEV_KERN_TEXT_FLAG = 256; // 0x100
     field public static final int DITHER_FLAG = 4; // 0x4
+    field public static final int EMBEDDED_BITMAP_TEXT_FLAG = 1024; // 0x400
     field public static final int FAKE_BOLD_TEXT_FLAG = 32; // 0x20
     field public static final int FILTER_BITMAP_FLAG = 2; // 0x2
     field public static final int HINTING_OFF = 0; // 0x0
@@ -9888,6 +9892,7 @@
     method public android.graphics.Shader.TileMode getTileModeY();
     method public boolean hasAntiAlias();
     method public boolean hasMipMap();
+    method public final boolean isAutoMirrored();
     method public void setAlpha(int);
     method public void setAntiAlias(boolean);
     method public void setColorFilter(android.graphics.ColorFilter);
@@ -9954,6 +9959,7 @@
     method public android.graphics.Region getTransparentRegion();
     method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void invalidateSelf();
+    method public boolean isAutoMirrored();
     method public boolean isStateful();
     method public final boolean isVisible();
     method public void jumpToCurrentState();
@@ -9964,6 +9970,7 @@
     method public static int resolveOpacity(int, int);
     method public void scheduleSelf(java.lang.Runnable, long);
     method public abstract void setAlpha(int);
+    method public void setAutoMirrored(boolean);
     method public void setBounds(int, int, int, int);
     method public void setBounds(android.graphics.Rect);
     method public final void setCallback(android.graphics.drawable.Drawable.Callback);
@@ -11650,6 +11657,7 @@
     field public static final int ADJUST_SAME = 0; // 0x0
     field public static final int AUDIOFOCUS_GAIN = 1; // 0x1
     field public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; // 0x2
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; // 0x4
     field public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; // 0x3
     field public static final int AUDIOFOCUS_LOSS = -1; // 0xffffffff
     field public static final int AUDIOFOCUS_LOSS_TRANSIENT = -2; // 0xfffffffe
@@ -18353,6 +18361,7 @@
     method public boolean hasHeaders();
     method public void invalidateHeaders();
     method public boolean isMultiPane();
+    method protected boolean isValidFragment(java.lang.String);
     method public void loadHeadersFromResource(int, java.util.List<android.preference.PreferenceActivity.Header>);
     method public void onBuildHeaders(java.util.List<android.preference.PreferenceActivity.Header>);
     method public android.content.Intent onBuildStartFragmentIntent(java.lang.String, android.os.Bundle, int, int);
@@ -25133,6 +25142,13 @@
     method public android.util.JsonWriter value(java.lang.Number) throws java.io.IOException;
   }
 
+  public abstract interface LayoutDirection {
+    field public static final int INHERIT = 2; // 0x2
+    field public static final int LOCALE = 3; // 0x3
+    field public static final int LTR = 0; // 0x0
+    field public static final int RTL = 1; // 0x1
+  }
+
   public final class Log {
     method public static int d(java.lang.String, java.lang.String);
     method public static int d(java.lang.String, java.lang.String, java.lang.Throwable);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 8d47236..0f988ed 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -67,6 +67,7 @@
     //  - increment _NUM_OP
     //  - add rows to sOpToSwitch, sOpNames, sOpPerms
     //  - add descriptive strings to Settings/res/values/arrays.xml
+    //  - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
 
     /** No operation specified. */
     public static final int OP_NONE = -1;
@@ -154,15 +155,17 @@
     public static final int OP_WAKE_LOCK = 40;
     /** Continually monitoring location data. */
     public static final int OP_MONITOR_LOCATION = 41;
+    /** Continually monitoring location data with a relatively high power request. */
+    public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
     /** @hide */
-    public static final int _NUM_OP = 42;
+    public static final int _NUM_OP = 43;
 
     /**
      * This maps each operation to the operation that serves as the
      * switch to determine whether it is allowed.  Generally this is
      * a 1:1 mapping, but for some things (like location) that have
      * multiple low-level operations being tracked that should be
-     * presented to hte user as one switch then this can be used to
+     * presented to the user as one switch then this can be used to
      * make them all controlled by the same single operation.
      */
     private static int[] sOpToSwitch = new int[] {
@@ -208,6 +211,7 @@
             OP_AUDIO_BLUETOOTH_VOLUME,
             OP_WAKE_LOCK,
             OP_COARSE_LOCATION,
+            OP_COARSE_LOCATION,
     };
 
     /**
@@ -257,6 +261,7 @@
             "AUDIO_BLUETOOTH_VOLUME",
             "WAKE_LOCK",
             "MONITOR_LOCATION",
+            "MONITOR_HIGH_POWER_LOCATION",
     };
 
     /**
@@ -306,6 +311,7 @@
             null, // no permission for changing bluetooth volume
             android.Manifest.permission.WAKE_LOCK,
             null, // no permission for generic location monitoring
+            null, // no permission for high power location monitoring
     };
 
     /**
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 6933a7a..f8a1d82 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -580,6 +580,10 @@
             if (clazz == null) {
                 // Class not found in the cache, see if it's real, and try to add it
                 clazz = context.getClassLoader().loadClass(fname);
+                if (!Fragment.class.isAssignableFrom(clazz)) {
+                    throw new InstantiationException("Trying to instantiate a class " + fname
+                            + " that is not a Fragment", new ClassCastException());
+                }
                 sClassMap.put(fname, clazz);
             }
             Fragment f = (Fragment)clazz.newInstance();
diff --git a/core/java/android/content/res/XmlResourceParser.java b/core/java/android/content/res/XmlResourceParser.java
index c59e6d4..5af49d4 100644
--- a/core/java/android/content/res/XmlResourceParser.java
+++ b/core/java/android/content/res/XmlResourceParser.java
@@ -26,7 +26,7 @@
  * an additional close() method on this interface for the client to indicate
  * when it is done reading the resource.
  */
-public interface XmlResourceParser extends XmlPullParser, AttributeSet {
+public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable {
     /**
      * Close this interface to the resource.  Calls on the interface are no
      * longer value after this call.
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index ec97efb..3e387d7 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -33,6 +33,7 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.LayoutInflater;
@@ -124,6 +125,8 @@
         PreferenceManager.OnPreferenceTreeClickListener,
         PreferenceFragment.OnPreferenceStartFragmentCallback {
 
+    private static final String TAG = "PreferenceActivity";
+
     // Constants for state save/restore
     private static final String HEADERS_TAG = ":android:headers";
     private static final String CUR_HEADER_TAG = ":android:cur_header";
@@ -132,6 +135,9 @@
     /**
      * When starting this activity, the invoking Intent can contain this extra
      * string to specify which fragment should be initially displayed.
+     * <p/>Starting from Key Lime Pie, when this argument is passed in, the PreferenceActivity
+     * will call isValidFragment() to confirm that the fragment class name is valid for this
+     * activity.
      */
     public static final String EXTRA_SHOW_FRAGMENT = ":android:show_fragment";
 
@@ -299,7 +305,7 @@
      * are valid.
      */
     public static final long HEADER_ID_UNDEFINED = -1;
-    
+
     /**
      * Description of a single Header item that the user can select.
      */
@@ -877,7 +883,27 @@
         } finally {
             if (parser != null) parser.close();
         }
+    }
 
+    /**
+     * Subclasses should override this method and verify that the given fragment is a valid type
+     * to be attached to this activity. The default implementation returns <code>true</code> prior
+     * to Key Lime Pie, <code>false</code> otherwise.
+     * @param fragmentName the class name of the Fragment about to be attached to this activity.
+     * @return true if the fragment class name is valid for this Activity and false otherwise.
+     */
+    protected boolean isValidFragment(String fragmentName) {
+        if (getApplicationInfo().targetSdkVersion  >= android.os.Build.VERSION_CODES.KEY_LIME_PIE) {
+            Log.w(TAG, "Subclasses of PreferenceActivity must override isValidFragment(String)"
+                    + " to verify that the Fragment class is valid! " + this.getClass().getName()
+                    + " has not checked if fragment " + fragmentName + " is valid.");
+            // Return true for now, but will eventually return false when all bundled apps
+            // have been modified. TODO: change to return false
+            return true;
+        } else {
+            Log.i(TAG, "PreferenceActivity built on pre-KLP launching fragment: " + fragmentName);
+            return true;
+        }
     }
 
     /**
@@ -1146,6 +1172,10 @@
     private void switchToHeaderInner(String fragmentName, Bundle args, int direction) {
         getFragmentManager().popBackStack(BACK_STACK_PREFS,
                 FragmentManager.POP_BACK_STACK_INCLUSIVE);
+        if (!isValidFragment(fragmentName)) {
+            throw new IllegalArgumentException("Invalid fragment for this activity: "
+                    + fragmentName);
+        }
         Fragment f = Fragment.instantiate(this, fragmentName, args);
         FragmentTransaction transaction = getFragmentManager().beginTransaction();
         transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
@@ -1275,6 +1305,10 @@
         if (mSinglePane) {
             startWithFragment(fragmentClass, args, resultTo, resultRequestCode, titleRes, 0);
         } else {
+            if (!isValidFragment(fragmentClass)) {
+                throw new IllegalArgumentException("Invalid fragment for this activity: "
+                        + fragmentClass);
+            }
             Fragment f = Fragment.instantiate(this, fragmentClass, args);
             if (resultTo != null) {
                 f.setTargetFragment(resultTo, resultRequestCode);
@@ -1291,7 +1325,7 @@
             transaction.commitAllowingStateLoss();
         }
     }
-    
+
     /**
      * Called by a preference panel fragment to finish itself.
      * 
diff --git a/core/java/android/util/LayoutDirection.java b/core/java/android/util/LayoutDirection.java
new file mode 100644
index 0000000..e37d2f2
--- /dev/null
+++ b/core/java/android/util/LayoutDirection.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util;
+
+/**
+ * An interface for defining layout directions. A layout direction can be left-to-right (LTR)
+ * or right-to-left (RTL). It can also be inherited (from a parent) or deduced from the default
+ * language script of a locale.
+ */
+public interface LayoutDirection {
+    /**
+     * Horizontal layout direction is from Left to Right.
+     */
+    public static final int LTR = 0;
+
+    /**
+     * Horizontal layout direction is from Right to Left.
+     */
+    public static final int RTL = 1;
+
+    /**
+     * Horizontal layout direction is inherited.
+     */
+    public static final int INHERIT = 2;
+
+    /**
+     * Horizontal layout direction is deduced from the default language script for the locale.
+     */
+    public static final int LOCALE = 3;
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 299c4a2..7624b56 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -51,6 +51,7 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
+import android.util.LayoutDirection;
 import android.util.Log;
 import android.util.LongSparseLongArray;
 import android.util.Pools.SynchronizedPool;
@@ -1801,25 +1802,25 @@
      * Horizontal layout direction of this view is from Left to Right.
      * Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_LTR = 0;
+    public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR;
 
     /**
      * Horizontal layout direction of this view is from Right to Left.
      * Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_RTL = 1;
+    public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL;
 
     /**
      * Horizontal layout direction of this view is inherited from its parent.
      * Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_INHERIT = 2;
+    public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT;
 
     /**
      * Horizontal layout direction of this view is from deduced from the default language
      * script for the locale. Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_LOCALE = 3;
+    public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE;
 
     /**
      * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index d924447..7e6bac4 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -28,7 +28,7 @@
  * @hide
  */
 public final class WebViewFactory {
-    private static final boolean DEFAULT_TO_EXPERIMENTAL_WEBVIEW = false;
+    private static final boolean DEFAULT_TO_EXPERIMENTAL_WEBVIEW = true;
     private static final String EXPERIMENTAL_PROPERTY_DEFAULT_OFF = "persist.sys.webview.exp";
     private static final String EXPERIMENTAL_PROPERTY_DEFAULT_ON  = "persist.sys.webview.exp_on";
 
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 33fd8ce..3e53b91 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -732,6 +732,15 @@
         }
     }
 
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+
+        if (mDrawable != null) {
+            mDrawable.setLayoutDirection(layoutDirection);
+        }
+    }
+
     private static final Matrix.ScaleToFit[] sS2FArray = {
         Matrix.ScaleToFit.FILL,
         Matrix.ScaleToFit.START,
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 816bb18..3181164 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2042,6 +2042,8 @@
             dr.mDrawableRightInitial = right;
         }
 
+        resetResolvedDrawables();
+        resolveDrawables();
         invalidate();
         requestLayout();
     }
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index e092fff..066d6c3 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.app;
 
+import android.animation.ValueAnimator;
+import android.view.ViewParent;
 import com.android.internal.view.ActionBarPolicy;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuPopupHelper;
@@ -75,7 +77,6 @@
 
     private ActionBarOverlayLayout mOverlayLayout;
     private ActionBarContainer mContainerView;
-    private ViewGroup mTopVisibilityView;
     private ActionBarView mActionView;
     private ActionBarContextView mContextView;
     private ActionBarContainer mSplitView;
@@ -125,12 +126,12 @@
         public void onAnimationEnd(Animator animation) {
             if (mContentAnimations && mContentView != null) {
                 mContentView.setTranslationY(0);
-                mTopVisibilityView.setTranslationY(0);
+                mContainerView.setTranslationY(0);
             }
             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                 mSplitView.setVisibility(View.GONE);
             }
-            mTopVisibilityView.setVisibility(View.GONE);
+            mContainerView.setVisibility(View.GONE);
             mContainerView.setTransitioning(false);
             mCurrentShowAnim = null;
             completeDeferredDestroyActionMode();
@@ -144,7 +145,16 @@
         @Override
         public void onAnimationEnd(Animator animation) {
             mCurrentShowAnim = null;
-            mTopVisibilityView.requestLayout();
+            mContainerView.requestLayout();
+        }
+    };
+
+    final ValueAnimator.AnimatorUpdateListener mUpdateListener =
+            new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            final ViewParent parent = mContainerView.getParent();
+            ((View) parent).invalidate();
         }
     };
 
@@ -153,7 +163,7 @@
         Window window = activity.getWindow();
         View decor = window.getDecorView();
         boolean overlayMode = mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
-        init(decor, overlayMode);
+        init(decor);
         if (!overlayMode) {
             mContentView = decor.findViewById(android.R.id.content);
         }
@@ -161,26 +171,21 @@
 
     public ActionBarImpl(Dialog dialog) {
         mDialog = dialog;
-        init(dialog.getWindow().getDecorView(), false);
+        init(dialog.getWindow().getDecorView());
     }
 
-    private void init(View decor, boolean overlayMode) {
+    private void init(View decor) {
         mContext = decor.getContext();
         mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
                 com.android.internal.R.id.action_bar_overlay_layout);
         if (mOverlayLayout != null) {
-            mOverlayLayout.setActionBar(this, overlayMode);
+            mOverlayLayout.setActionBar(this);
         }
         mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
         mContextView = (ActionBarContextView) decor.findViewById(
                 com.android.internal.R.id.action_context_bar);
         mContainerView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.action_bar_container);
-        mTopVisibilityView = (ViewGroup)decor.findViewById(
-                com.android.internal.R.id.top_action_bar);
-        if (mTopVisibilityView == null) {
-            mTopVisibilityView = mContainerView;
-        }
         mSplitView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.split_action_bar);
 
@@ -675,29 +680,30 @@
         if (mCurrentShowAnim != null) {
             mCurrentShowAnim.end();
         }
-        mTopVisibilityView.setVisibility(View.VISIBLE);
+        mContainerView.setVisibility(View.VISIBLE);
 
         if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                 || fromSystem)) {
-            mTopVisibilityView.setTranslationY(0); // because we're about to ask its window loc
-            float startingY = -mTopVisibilityView.getHeight();
+            mContainerView.setTranslationY(0); // because we're about to ask its window loc
+            float startingY = -mContainerView.getHeight();
             if (fromSystem) {
                 int topLeft[] = {0, 0};
-                mTopVisibilityView.getLocationInWindow(topLeft);
+                mContainerView.getLocationInWindow(topLeft);
                 startingY -= topLeft[1];
             }
-            mTopVisibilityView.setTranslationY(startingY);
+            mContainerView.setTranslationY(startingY);
             AnimatorSet anim = new AnimatorSet();
-            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView,
-                    "translationY", 0));
+            ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, 0);
+            a.addUpdateListener(mUpdateListener);
+            AnimatorSet.Builder b = anim.play(a);
             if (mContentAnimations && mContentView != null) {
-                b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
+                b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
                         startingY, 0));
             }
             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                 mSplitView.setTranslationY(mSplitView.getHeight());
                 mSplitView.setVisibility(View.VISIBLE);
-                b.with(ObjectAnimator.ofFloat(mSplitView, "translationY", 0));
+                b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y, 0));
             }
             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
                     com.android.internal.R.interpolator.decelerate_cubic));
@@ -713,8 +719,8 @@
             mCurrentShowAnim = anim;
             anim.start();
         } else {
-            mTopVisibilityView.setAlpha(1);
-            mTopVisibilityView.setTranslationY(0);
+            mContainerView.setAlpha(1);
+            mContainerView.setTranslationY(0);
             if (mContentAnimations && mContentView != null) {
                 mContentView.setTranslationY(0);
             }
@@ -737,24 +743,25 @@
 
         if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                 || fromSystem)) {
-            mTopVisibilityView.setAlpha(1);
+            mContainerView.setAlpha(1);
             mContainerView.setTransitioning(true);
             AnimatorSet anim = new AnimatorSet();
-            float endingY = -mTopVisibilityView.getHeight();
+            float endingY = -mContainerView.getHeight();
             if (fromSystem) {
                 int topLeft[] = {0, 0};
-                mTopVisibilityView.getLocationInWindow(topLeft);
+                mContainerView.getLocationInWindow(topLeft);
                 endingY -= topLeft[1];
             }
-            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView,
-                    "translationY", endingY));
+            ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, endingY);
+            a.addUpdateListener(mUpdateListener);
+            AnimatorSet.Builder b = anim.play(a);
             if (mContentAnimations && mContentView != null) {
-                b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
+                b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
                         0, endingY));
             }
             if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
                 mSplitView.setAlpha(1);
-                b.with(ObjectAnimator.ofFloat(mSplitView, "translationY",
+                b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y,
                         mSplitView.getHeight()));
             }
             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index f359146..88ff7e2 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.widget;
 
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.Log;
 import android.view.ViewGroup;
 import com.android.internal.app.ActionBarImpl;
 
@@ -31,18 +35,23 @@
  * has request that its layout ignore them.
  */
 public class ActionBarOverlayLayout extends ViewGroup {
+    private static final String TAG = "ActionBarOverlayLayout";
+
     private int mActionBarHeight;
     private ActionBarImpl mActionBar;
     private int mWindowVisibility = View.VISIBLE;
 
     // The main UI elements that we handle the layout of.
     private View mContent;
-    private View mActionBarTop;
     private View mActionBarBottom;
+    private ActionBarContainer mActionBarTop;
 
     // Some interior UI elements.
-    private ActionBarContainer mContainerView;
-    private ActionBarView mActionView;
+    private ActionBarView mActionBarView;
+
+    // Content overlay drawable - generally the action bar's shadow
+    private Drawable mWindowContentOverlay;
+    private boolean mIgnoreWindowContentOverlay;
 
     private boolean mOverlayMode;
     private int mLastSystemUiVisibility;
@@ -53,8 +62,9 @@
     private final Rect mInnerInsets = new Rect();
     private final Rect mLastInnerInsets = new Rect();
 
-    static final int[] mActionBarSizeAttr = new int [] {
-            com.android.internal.R.attr.actionBarSize
+    static final int[] ATTRS = new int [] {
+            com.android.internal.R.attr.actionBarSize,
+            com.android.internal.R.attr.windowContentOverlay
     };
 
     public ActionBarOverlayLayout(Context context) {
@@ -68,14 +78,18 @@
     }
 
     private void init(Context context) {
-        TypedArray ta = getContext().getTheme().obtainStyledAttributes(mActionBarSizeAttr);
+        TypedArray ta = getContext().getTheme().obtainStyledAttributes(ATTRS);
         mActionBarHeight = ta.getDimensionPixelSize(0, 0);
+        mWindowContentOverlay = ta.getDrawable(1);
+        setWillNotDraw(mWindowContentOverlay == null);
         ta.recycle();
+
+        mIgnoreWindowContentOverlay = context.getApplicationInfo().targetSdkVersion <
+                Build.VERSION_CODES.KEY_LIME_PIE;
     }
 
-    public void setActionBar(ActionBarImpl impl, boolean overlayMode) {
+    public void setActionBar(ActionBarImpl impl) {
         mActionBar = impl;
-        mOverlayMode = overlayMode;
         if (getWindowToken() != null) {
             // This is being initialized after being added to a window;
             // make sure to update all state now.
@@ -88,6 +102,18 @@
         }
     }
 
+    public void setOverlayMode(boolean overlayMode) {
+        mOverlayMode = overlayMode;
+
+        /*
+         * Drawing the window content overlay was broken before K so starting to draw it
+         * again unexpectedly will cause artifacts in some apps. They should fix it.
+         */
+        mIgnoreWindowContentOverlay = overlayMode &&
+                getContext().getApplicationInfo().targetSdkVersion <
+                        Build.VERSION_CODES.KEY_LIME_PIE;
+    }
+
     public void setShowingForActionMode(boolean showing) {
         if (showing) {
             // Here's a fun hack: if the status bar is currently being hidden,
@@ -253,7 +279,7 @@
             // we can't depend on the size currently reported by it -- this must remain constant.
             topInset = mActionBarHeight;
             if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) {
-                View tabs = mContainerView.getTabContainer();
+                View tabs = mActionBarTop.getTabContainer();
                 if (tabs != null) {
                     // If tabs are not embedded, increase space on top to account for them.
                     topInset += mActionBarHeight;
@@ -265,7 +291,7 @@
             topInset = mActionBarTop.getMeasuredHeight();
         }
 
-        if (mActionView.isSplitActionBar()) {
+        if (mActionBarView.isSplitActionBar()) {
             // If action bar is split, adjust bottom insets for it.
             if (mActionBarBottom != null) {
                 if (stable) {
@@ -352,6 +378,18 @@
     }
 
     @Override
+    public void draw(Canvas c) {
+        super.draw(c);
+        if (mWindowContentOverlay != null && !mIgnoreWindowContentOverlay) {
+            final int top = mActionBarTop.getVisibility() == VISIBLE ?
+                    (int) (mActionBarTop.getBottom() + mActionBarTop.getTranslationY() + 0.5f) : 0;
+            mWindowContentOverlay.setBounds(0, top, getWidth(),
+                    top + mWindowContentOverlay.getIntrinsicHeight());
+            mWindowContentOverlay.draw(c);
+        }
+    }
+
+    @Override
     public boolean shouldDelayChildPressedState() {
         return false;
     }
@@ -359,10 +397,9 @@
     void pullChildren() {
         if (mContent == null) {
             mContent = findViewById(com.android.internal.R.id.content);
-            mActionBarTop = findViewById(com.android.internal.R.id.top_action_bar);
-            mContainerView = (ActionBarContainer)findViewById(
+            mActionBarTop = (ActionBarContainer)findViewById(
                     com.android.internal.R.id.action_bar_container);
-            mActionView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+            mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
             mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
         }
     }
diff --git a/core/res/res/layout-xlarge/screen_action_bar.xml b/core/res/res/layout-xlarge/screen_action_bar.xml
index 4f286780..e495e53 100644
--- a/core/res/res/layout-xlarge/screen_action_bar.xml
+++ b/core/res/res/layout-xlarge/screen_action_bar.xml
@@ -28,30 +28,23 @@
     <FrameLayout android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
-    <LinearLayout android:id="@+id/top_action_bar"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content">
-        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
+    <com.android.internal.widget.ActionBarContainer
+        android:id="@+id/action_bar_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        style="?android:attr/actionBarStyle"
+        android:gravity="top">
+        <com.android.internal.widget.ActionBarView
+            android:id="@+id/action_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            style="?android:attr/actionBarStyle"
-            android:gravity="top">
-            <com.android.internal.widget.ActionBarView
-                android:id="@+id/action_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                style="?android:attr/actionBarStyle" />
-            <com.android.internal.widget.ActionBarContextView
-                android:id="@+id/action_context_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:visibility="gone"
-                style="?android:attr/actionModeStyle" />
-        </com.android.internal.widget.ActionBarContainer>
-        <ImageView android:src="?android:attr/windowContentOverlay"
-                   android:scaleType="fitXY"
-                   android:layout_width="match_parent"
-                   android:layout_height="wrap_content" />
-    </LinearLayout>
+            style="?android:attr/actionBarStyle" />
+        <com.android.internal.widget.ActionBarContextView
+            android:id="@+id/action_context_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?android:attr/actionModeStyle" />
+    </com.android.internal.widget.ActionBarContainer>
 </com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index e310bf5..b1889a2 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -25,34 +25,27 @@
     android:layout_height="match_parent"
     android:splitMotionEvents="false">
     <FrameLayout android:id="@android:id/content"
+                 android:layout_width="match_parent"
+                 android:layout_height="match_parent" />
+    <com.android.internal.widget.ActionBarContainer
+        android:id="@+id/action_bar_container"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-    <LinearLayout android:id="@+id/top_action_bar"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content">
-        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        style="?android:attr/actionBarStyle"
+        android:gravity="top">
+        <com.android.internal.widget.ActionBarView
+            android:id="@+id/action_bar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            style="?android:attr/actionBarStyle"
-            android:gravity="top">
-            <com.android.internal.widget.ActionBarView
-                android:id="@+id/action_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                style="?android:attr/actionBarStyle" />
-            <com.android.internal.widget.ActionBarContextView
-                android:id="@+id/action_context_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:visibility="gone"
-                style="?android:attr/actionModeStyle" />
-        </com.android.internal.widget.ActionBarContainer>
-        <ImageView android:src="?android:attr/windowContentOverlay"
-                   android:scaleType="fitXY"
-                   android:layout_width="match_parent"
-                   android:layout_height="wrap_content" />
-    </LinearLayout>
+            style="?android:attr/actionBarStyle" />
+        <com.android.internal.widget.ActionBarContextView
+            android:id="@+id/action_context_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?android:attr/actionModeStyle" />
+    </com.android.internal.widget.ActionBarContainer>
     <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4cad232..67a32fd 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3905,6 +3905,10 @@
              value is false.  See
              {@link android.graphics.drawable.Drawable#setVisible}. -->
         <attr name="visible" format="boolean" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left).  See
+             {@link android.graphics.drawable.Drawable#setAutoMirrored}. -->
+        <attr name="autoMirrored" format="boolean" />
     </declare-styleable>
 
     <!-- Drawable used to render several states. Each state is represented by
@@ -3932,6 +3936,9 @@
         <attr name="enterFadeDuration" format="integer" />
         <!-- Amount of time (in milliseconds) to fade out an old state drawable. -->
         <attr name="exitFadeDuration" format="integer" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored"/>
     </declare-styleable>
 
     <!-- Drawable used to render several animated frames. -->
@@ -4083,6 +4090,9 @@
             <!-- The layer has translucent pixels. -->
             <enum name="translucent" value="-3" />
         </attr>
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored" />
     </declare-styleable>
 
     <!-- Describes an item (or child) of a LayerDrawable. -->
@@ -4172,6 +4182,9 @@
             {@link android.graphics.Bitmap#setHasMipMap(boolean)} for more information.
             Default value is false. -->
         <attr name="mipMap" format="boolean" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored" />
     </declare-styleable>
 
     <!-- Drawable used to draw 9-patches. -->
@@ -4182,6 +4195,9 @@
              same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
              an RGB 565 screen). -->
         <attr name="dither" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored" />
     </declare-styleable>
 
     <!-- Drawable used to draw a single color. -->
@@ -6007,4 +6023,9 @@
         <attr name="digit" format="integer" />
         <attr name="textView" format="reference" />
     </declare-styleable>
+
+    <declare-styleable name="DocumentsProviderInfo">
+        <attr name="customRoots" format="boolean" />
+    </declare-styleable>
+
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b9c3638..80c9184 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2070,4 +2070,7 @@
   <public type="attr" name="vendor" />
   <public type="attr" name="category" />
   <public type="attr" name="isAsciiCapable" />
+  <public type="attr" name="customRoots" />
+  <public type="attr" name="autoMirrored" />
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 008c334..3e29221 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -175,7 +175,6 @@
   <java-symbol type="id" name="to_common" />
   <java-symbol type="id" name="to_org" />
   <java-symbol type="id" name="to_org_unit" />
-  <java-symbol type="id" name="top_action_bar" />
   <java-symbol type="id" name="topPanel" />
   <java-symbol type="id" name="up" />
   <java-symbol type="id" name="value" />
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index c23ee10..5f0779c 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -21,6 +21,9 @@
 - from: /sdk/compatibility-library.html
   to: /tools/support-library/index.html
 
+- from: /training/basics/fragments/support-lib.html
+  to: /tools/support-library/setup.html
+
 - from: /sdk/eclipse-adt.html
   to: /tools/sdk/eclipse-adt.html
 
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 880d7e9..6e4a03c 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -48,7 +48,7 @@
 the Android platform.</p>
 
 <p>For information about how to target your application to devices based on
-platform version, read <a 
+platform version, read <a
 href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different
 Platform Versions</a>.</p>
 
@@ -57,7 +57,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 14-day period ending on July 8, 2013.
+<p style="clear:both"><em>Data collected during a 14-day period ending on August 1, 2013.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -83,7 +83,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 14-day period ending on July 8, 2013
+<p style="clear:both"><em>Data collected during a 14-day period ending on August 1, 2013
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
@@ -130,7 +130,7 @@
 
 
 
-<p style="clear:both"><em>Data collected during a 14-day period ending on July 8, 2013</em></p>
+<p style="clear:both"><em>Data collected during a 14-day period ending on August 1, 2013</em></p>
 
 
 
@@ -148,7 +148,7 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?chl=Eclair%7CFroyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean&chco=c4df9b%2C6fad0c&chd=t%3A1.5%2C3.1%2C34.1%2C0.1%2C23.3%2C37.9&chf=bg%2Cs%2C00000000&chs=500x250&cht=p",
+    "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chl=Eclair%7CFroyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean&chf=bg%2Cs%2C00000000&chd=t%3A1.3%2C2.5%2C33.1%2C0.1%2C22.5%2C40.5&chco=c4df9b%2C6fad0c",
     "data": [
       {
         "api": 4,
@@ -158,17 +158,22 @@
       {
         "api": 7,
         "name": "Eclair",
-        "perc": "1.4"
+        "perc": "1.2"
       },
       {
         "api": 8,
         "name": "Froyo",
-        "perc": "3.1"
+        "perc": "2.5"
+      },
+      {
+        "api": 9,
+        "name": "Gingerbread",
+        "perc": "0.1"
       },
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "34.1"
+        "perc": "33.0"
       },
       {
         "api": 13,
@@ -178,17 +183,17 @@
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "23.3"
+        "perc": "22.5"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "32.3"
+        "perc": "34.0"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "5.6"
+        "perc": "6.5"
       }
     ]
   }
@@ -204,21 +209,21 @@
     "data": {
       "Large": {
         "hdpi": "0.4",
-        "ldpi": "0.6",
+        "ldpi": "0.5",
         "mdpi": "3.2",
-        "tvdpi": "1.0",
+        "tvdpi": "1.1",
         "xhdpi": "0.5"
       },
       "Normal": {
-        "hdpi": "34.9",
+        "hdpi": "34.5",
         "ldpi": "0.1",
-        "mdpi": "16.0",
-        "xhdpi": "24.0",
-        "xxhdpi": "4.9"
+        "mdpi": "15.9",
+        "xhdpi": "23.9",
+        "xxhdpi": "5.7"
       },
       "Small": {
         "hdpi": "0.1",
-        "ldpi": "9.9"
+        "ldpi": "9.7"
       },
       "Xlarge": {
         "hdpi": "0.2",
@@ -226,8 +231,8 @@
         "xhdpi": "0.1"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chco=c4df9b%2C6fad0c&chd=t%3A10.7%2C23.3%2C1.0%2C35.6%2C24.6%2C4.9&chf=bg%2Cs%2C00000000&chs=400x250&cht=p",
-    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chco=c4df9b%2C6fad0c&chd=t%3A4.4%2C5.7%2C79.9%2C10.1&chf=bg%2Cs%2C00000000&chs=400x250&cht=p"
+    "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chf=bg%2Cs%2C00000000&chd=t%3A10.3%2C23.2%2C1.1%2C35.2%2C24.5%2C5.7&chco=c4df9b%2C6fad0c",
+    "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=Xlarge%7CLarge%7CNormal%7CSmall&chf=bg%2Cs%2C00000000&chd=t%3A4.4%2C5.7%2C80.2%2C9.8&chco=c4df9b%2C6fad0c"
   }
 ];
 
@@ -236,14 +241,14 @@
 var VERSION_NAMES =
 [
   {"api":0},{"api":1},{"api":2},{"api":3},
-  { 
+  {
     "api":4,
     "link":"<a href='/about/versions/android-1.6.html'>1.6</a>",
     "codename":"Donut",
   },
   { "api":5},
   { "api":6},
-  { 
+  {
     "api":7,
     "link":"<a href='/about/versions/android-2.1.html'>2.1</a>",
     "codename":"Eclair",
diff --git a/docs/html/about/versions/android-4.3.jd b/docs/html/about/versions/android-4.3.jd
index bccc9d5..e18c285 100644
--- a/docs/html/about/versions/android-4.3.jd
+++ b/docs/html/about/versions/android-4.3.jd
@@ -19,6 +19,7 @@
     <ol>
       <li><a href="#BehaviorsIntents">If your app uses implicit intents...</a></li>
       <li><a href="#BehaviorsAccounts">If your app depends on accounts...</a></li>
+      <li><a href="#BehaviorsVideoView">If your app uses VideoView...</a></li>
     </ol>
   </li>
   <li><a href="#RestrictedProfiles">Restricted Profiles</a>
@@ -213,6 +214,21 @@
 below about <a href="#AccountsInProfile">Supporting accounts in a restricted profile</a>.</p>
 
 
+<h3 id="BehaviorsVideoView">If your app uses VideoView...</h3>
+
+<p>Your video might appear smaller on Android 4.3.</p>
+
+<p>On previous versions of Android, the {@link android.widget.VideoView} widget incorrectly
+calculated the {@code "wrap_content"} value for {@link android.R.attr#layout_height} and {@link
+android.R.attr#layout_width} to be the same as {@code "match_parent"}. So while using {@code
+"wrap_content"} for the height or width may have previously provided your desired video layout,
+doing so may result in a much smaller video on Android 4.3 and higher. To fix the issue, replace
+{@code "wrap_content"} with {@code "match_parent"} and verify your video appears as expected on
+Android 4.3 as well as on older versions.</p>
+
+
+
+
 
 
 <h2 id="RestrictedProfiles">Restricted Profiles</h2>
diff --git a/docs/html/distribute/googleplay/edu/start.jd b/docs/html/distribute/googleplay/edu/start.jd
index 419d5ea..78b8739 100644
--- a/docs/html/distribute/googleplay/edu/start.jd
+++ b/docs/html/distribute/googleplay/edu/start.jd
@@ -57,8 +57,8 @@
 policies</a>, the <a
 href="http://play.google.com/about/developer-distribution-agreement.html"
 target="_policies">developer agreement</a>,  and <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.
-html" target="_policies">Google Play for Education Addendum</a>.</p>
+href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
+target="_policies">Google Play for Education Addendum</a>.</p>
 
 <h3 id="developing">2. Design and develop a great app for education</h3>
 
@@ -129,8 +129,8 @@
 href="http://play.google.com/about/developer-distribution-agreement.html"
 target="_policies">Developer Distribution Agreement</a>,
 including a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.
-html" target="_policies">Google Play for Education
+href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
+target="_policies">Google Play for Education
 Addendum</a>. If you are not familiar with these policy documents or the
 Addendum, make sure to read them before opting-in. </p>
 
diff --git a/docs/html/distribute/googleplay/publish/localizing.jd b/docs/html/distribute/googleplay/publish/localizing.jd
index a7f1976..29b27c8 100644
--- a/docs/html/distribute/googleplay/publish/localizing.jd
+++ b/docs/html/distribute/googleplay/publish/localizing.jd
@@ -111,8 +111,8 @@
 
 <p>In cases where your UI can't accommodate text in one of your target
 languages, you can create an <a
-href="{@docRoot}guide/topics/resources/providing-resources.
-html#AlternativeResources">alternative layout</a> for that language only.
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">alternative
+layout</a> for that language only.
 Android makes it easy to declare sets of layouts and other resources to load for
 specific languages, locales, screen sizes, and so on, simply by tagging them
 with the appropriate resource qualifiers. </p>
diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
index 36e7345..fe046d4 100644
--- a/docs/html/distribute/googleplay/quality/tablet.jd
+++ b/docs/html/distribute/googleplay/quality/tablet.jd
@@ -501,8 +501,11 @@
 
 <p>To ensure the broadest possible distribution to tablets, make sure that your
 app properly targets the Android versions that support tablets. Initial support for
-tablets was added in <a href="{@docRoot}about/versions/android-3.0">Android 3.0</a> (API level 11). Unified UI
-framework support for tablets, phones, and other devices was introduced in <a href="{@docRoot}about/versions/android-4.0">Android 4.0</a> (API level 14) and is supported in later versions.
+tablets was added in <a href="{@docRoot}about/versions/android-3.0.html">Android 3.0</a>
+(API level 11). Unified UI
+framework support for tablets, phones, and other devices was introduced in <a
+href="{@docRoot}about/versions/android-4.0.html">Android 4.0</a> (API level 14) and is
+supported in later versions.
 
 <p>You can set the app's
 range of targeted Android versions in the manifest file, in the
@@ -809,7 +812,7 @@
     </li>
     <li>
       <a href=
-      "{@docRoot}distribute/googleplay/promote/device-art.html">Device Art
+      "{@docRoot}distribute/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>
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 0cadbd2..9c5961c 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -29,7 +29,7 @@
 <h2>See Also</h2>
 
 <ol class="toc">
-<li><a href="{@docRoot}google/play-services/gcm/gs.html">Getting Started</a></li>
+<li><a href="{@docRoot}google/gcm/gs.html">Getting Started</a></li>
 <li><a href="https://services.google.com/fb/forms/gcm/" class="external-link" target="_android">CCS and User Notifications Signup Form</a></li>
 </ol>
 
diff --git a/docs/html/google/gcm/notifications.jd b/docs/html/google/gcm/notifications.jd
index df171cf..5171850 100644
--- a/docs/html/google/gcm/notifications.jd
+++ b/docs/html/google/gcm/notifications.jd
@@ -29,7 +29,7 @@
 <h2>See Also</h2>
 
 <ol class="toc">
-<li><a href="{@docRoot}google/play-services/gcm/gs.html">Getting Started</a></li>
+<li><a href="{@docRoot}google/gcm/gs.html">Getting Started</a></li>
 <li><a href="https://services.google.com/fb/forms/gcm/" class="external-link" target="_android">CCS and User Notifications Signup Form</a></li>
 </ol>
 
diff --git a/docs/html/google/play-services/gcm.jd b/docs/html/google/play-services/gcm.jd
deleted file mode 100644
index a9da73f..0000000
--- a/docs/html/google/play-services/gcm.jd
+++ /dev/null
@@ -1,69 +0,0 @@
-page.title=GCM Extensions
-page.tags="cloud","push","messaging"
-header.hide=1
-@jd:body
-
-<div class="landing-banner">
-        
-<div class="col-6">
-  <img src="" alt="">
-</div>
-<div class="col-6">
-
-  <h1 itemprop="name" style="margin-bottom:0;">GCM Extensions for Android</h1>
-   <p itemprop="description">
-GCM extension APIs make it easier to take advantage of enhanced messaging capabilities in your apps, and they can help you simplify your implementation of Google Cloud Messaging.</p>
-
-<p>You can use GCM extensions in any new or existing GCM implementation to build powerful multi-device messaging and presence features for your users.</p>
-
-</div>
-</div>
-
-
-<div class="landing-docs">
-  <div class="col-6 normal-links">
-    <h3 style="clear:left">Key Developer Features</h3>
-
-    <h4>Faster, easier GCM setup</h4>
-    <p>Streamlined registration makes it simple and fast to add GCM support to your Android app. <a href="{@docRoot}google/play-services/gcm/gs.html">Learn more &raquo;</a></p>
-
-
-    <h4>Bidirectional messaging over XMPP</h4>
-    <p>GCM's Cloud Connection Service (CCS) lets you communicate with Android devices over a persistent XMPP connection. Communication is asynchronous and bidirectional, and you can use the service in tandem with existing GCM APIs. You can use <a href="https://services.google.com/fb/forms/gcm/">this form</a> to sign up for CCS. <a href="{@docRoot}google/gcm/ccs.html">Learn more &raquo;</a></p>
-
-   <!-- <p>To get started, sign up using <a href="https://services.google.com/fb/forms/gcm/">this form</a> and then learn how to <a href="{@docRoot}google/gcm/ccs.html">send XMPP messages</a>.</p> -->
-    
-    <h4>Seamless multi-device messaging</h4>
-    <p>New user notifications let you send a single message simultaneously to all of a user's Android devices. </p>
-
-    <p>GCM lets you map all of a user's multiple devices to a single notification key, which you can then reference as the target for messages that you are sending to that user. 
-    <a href="{@docRoot}google/gcm/notifications.html">Learn more &raquo;</a></p>
-    </a>
-    
-
-  </div>
-
-
-  <div class="col-6 normal-links">
-    <h3 style="clear:left">Getting Started</h3>
-    <h4>1. Get the Google Play services SDK</h4>
-    <p>The GCM Extension APIs are part of the Google Play services platform. To use the APIs, <a href="{@docRoot}google/play-services/setup.html">set up
-      the Google Play services SDK</a>. 
-    </p>
-            
-    <h4>2. Create a Google APIs project</h4>
-    
-    <p>To use GCM, you need to set up a Google APIs project and get an application key. If you are already using GCM, you can use your existing project and key. <a href="{@docRoot}google/play-services/gcm/gs.html#google_apis">Learn more &raquo;</a></p>
-
-    <h4>3. Set up GCM in your app</h4>
-    
-    <p>To send and receive messages over GCM, you need to update the manifest and add code to register with GCM and handle messages. See <a href="{@docRoot}google/play-services/gcm/gs.html#manifest">Get Started</a> for details.
-    </p>
-    
-    <h4>4. Integrate GCM with your backend servers</h4>
-
-    <p>A complete GCM implementation requires a server-side implementation, in addition to the client implementation in your app. For complete information, make sure to read the <a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging documentation</a>. 
-
-  </div>
-
-</div>
diff --git a/docs/html/google/play/billing/v2/billing_subscriptions.jd b/docs/html/google/play/billing/v2/billing_subscriptions.jd
index db18a53..9c86e20 100644
--- a/docs/html/google/play/billing/v2/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/v2/billing_subscriptions.jd
@@ -11,12 +11,12 @@
         <li><a href="#model">Application Model</a></li>
         <li><a href="#token">Purchase Token</a></li>
         <li><a href="#version">Checking the In-app Billing API Version</a></li>
-        <li><a href="purchase">Purchasing a Subscription</a></li>
+        <li><a href="#purchase">Purchasing a Subscription</a></li>
         <li><a href="#restore">Restoring Transactions</a></li>
         <li><a href="#validity">Checking Subscription Validity</a></li>
         <li><a href="#viewstatus">Letting Users Cancel or View Status</a></li>
         <li><a href="#purchase-state-changes">Recurring Billing and Changes in Purchase State</a></li>
-        <li><a href="modifying">Modifying Your App for Subscriptions</a></li>
+        <li><a href="#modifying">Modifying Your App for Subscriptions</a></li>
    </ol>
 </div>
 </div>
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 10ab61f..3173ff1 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -1,5 +1,5 @@
 page.title=Action Bar
-page.tags="actionbar","menu"
+page.tags="actionbar","menu","tabs"
 
 @jd:body
 
diff --git a/docs/html/images/training/basics/actionbar-actions.png b/docs/html/images/training/basics/actionbar-actions.png
new file mode 100644
index 0000000..5195a8c
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-actions.png
Binary files differ
diff --git a/docs/html/images/training/basics/actionbar-basic.png b/docs/html/images/training/basics/actionbar-basic.png
new file mode 100644
index 0000000..ba77659
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-basic.png
Binary files differ
diff --git a/docs/html/images/training/basics/actionbar-overlay@2x.png b/docs/html/images/training/basics/actionbar-overlay@2x.png
new file mode 100644
index 0000000..7014a19
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-overlay@2x.png
Binary files differ
diff --git a/docs/html/images/training/basics/actionbar-theme-custom-tabs@2x.png b/docs/html/images/training/basics/actionbar-theme-custom-tabs@2x.png
new file mode 100644
index 0000000..ea8c93b
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-theme-custom-tabs@2x.png
Binary files differ
diff --git a/docs/html/images/training/basics/actionbar-theme-custom@2x.png b/docs/html/images/training/basics/actionbar-theme-custom@2x.png
new file mode 100644
index 0000000..bb6f1a4
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-theme-custom@2x.png
Binary files differ
diff --git a/docs/html/images/training/basics/actionbar-theme-dark-solid@2x.png b/docs/html/images/training/basics/actionbar-theme-dark-solid@2x.png
new file mode 100644
index 0000000..bd16ffe
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-theme-dark-solid@2x.png
Binary files differ
diff --git a/docs/html/images/training/basics/actionbar-theme-dark@2x.png b/docs/html/images/training/basics/actionbar-theme-dark@2x.png
new file mode 100644
index 0000000..88c3b22
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-theme-dark@2x.png
Binary files differ
diff --git a/docs/html/images/training/basics/actionbar-theme-light-darkactionbar@2x.png b/docs/html/images/training/basics/actionbar-theme-light-darkactionbar@2x.png
new file mode 100644
index 0000000..5509e16
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-theme-light-darkactionbar@2x.png
Binary files differ
diff --git a/docs/html/images/training/basics/actionbar-theme-light-solid@2x.png b/docs/html/images/training/basics/actionbar-theme-light-solid@2x.png
new file mode 100644
index 0000000..810ef46
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-theme-light-solid@2x.png
Binary files differ
diff --git a/docs/html/images/training/basics/actionbar-theme-light@2x.png b/docs/html/images/training/basics/actionbar-theme-light@2x.png
new file mode 100644
index 0000000..a0af43a
--- /dev/null
+++ b/docs/html/images/training/basics/actionbar-theme-light@2x.png
Binary files differ
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
index 6291a3e..3a416f9 100644
--- a/docs/html/sitemap.txt
+++ b/docs/html/sitemap.txt
@@ -362,7 +362,6 @@
 http://developer.android.com/training/basics/supporting-devices/languages.html
 http://developer.android.com/training/basics/supporting-devices/screens.html
 http://developer.android.com/training/basics/supporting-devices/platforms.html
-http://developer.android.com/training/basics/fragments/support-lib.html
 http://developer.android.com/training/basics/fragments/creating.html
 http://developer.android.com/training/basics/fragments/fragment-ui.html
 http://developer.android.com/training/basics/fragments/communicating.html
diff --git a/docs/html/tools/support-library/setup.jd b/docs/html/tools/support-library/setup.jd
index 6cca897..73d9468 100644
--- a/docs/html/tools/support-library/setup.jd
+++ b/docs/html/tools/support-library/setup.jd
@@ -10,7 +10,7 @@
     <ol>
       <li><a href="#download">Downloading the Support Library</a></li>
       <li><a href="#choosing">Choosing Support Libraries</a></li>
-      <li><a href="add-library">Adding Support Libraries</a>
+      <li><a href="#add-library">Adding Support Libraries</a>
         <ol>
           <li><a href="#libs-without-res">Adding libraries without resources</a></li>
           <li><a href="#libs-with-res">Adding libraries with resources</a></li>
@@ -90,9 +90,9 @@
   each Support Library you want to use.</p>
 
 <p>Some Support Libraries contain resources beyond compiled code classes, such as images or XML
-  files. For example, the <a href="tools/support-library/features.html#v7-appcompat">v7
-  appcompat</a> and <a href="tools/support-library/features.html#v7-gridlayout">v7 gridlayout</a>
-  libraries include resources.</p>
+  files. For example, the <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
+  appcompat</a> and <a href="{@docRoot}tools/support-library/features.html#v7-gridlayout">v7
+  gridlayout</a> libraries include resources.</p>
 
 <p>If you are not sure if a library contains resources, check the
   <a href="{@docRoot}tools/support-library/features.html">Support Library Features</a> page.
@@ -149,7 +149,9 @@
 
 <h3 id="libs-with-res">Adding libraries with resources</h3>
 
-<p>To add a Support Library with resources to your application project:</p>
+<p>To add a Support Library with resources (such as
+  <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
+  appcompat</a> for action bar) to your application project:</p>
 
 <div class="toggle-content closed">
   <p style="margin-top:5px"><a href="#" onclick="return toggleContent(this)">
diff --git a/docs/html/training/basics/actionbar/adding-buttons.jd b/docs/html/training/basics/actionbar/adding-buttons.jd
new file mode 100644
index 0000000..5fb0d59
--- /dev/null
+++ b/docs/html/training/basics/actionbar/adding-buttons.jd
@@ -0,0 +1,210 @@
+page.title=Adding Action Buttons
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+  <div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#XML">Specify the Actions in XML</a></li>
+  <li><a href="#AddActions">Add the Actions to the Action Bar</a></li>
+  <li><a href="#Respond">Respond to Action Buttons</a></li>
+  <li><a href="#UpNav">Add Up Button for Low-level Activities</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}training/implementing-navigation/ancestral.html">Providing Up
+  Navigation</a></li>
+  </div>
+</div>
+
+
+
+<p>The action bar allows you to add buttons for the most important action
+items relating to the app's current
+context. Those that appear directly in the action bar with an icon and/or text are known
+as <em>action buttons</em>. Actions that can't fit in the action bar or aren't
+important enough are hidden in the action overflow.</p>
+
+<img src="{@docRoot}images/training/basics/actionbar-actions.png" height="100" alt=""/>
+<p class="img-caption"><strong>Figure 1.</strong> An action bar with an action button
+for Search and the action overflow, which reveals additional actions.</a>
+
+
+<h2 id="XML">Specify the Actions in XML</h2>
+
+<p>All action buttons and other items available in the action overflow are defined
+in an XML <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. To add
+actions to the action bar, create a new XML file in your project's
+{@code res/menu/} directory.</p>
+
+<p>Add an {@code &lt;item>} element for each item you want to include in the action bar.
+For example:</p>
+
+<p class="code-caption">res/menu/main_activity_actions.xml</p>
+<pre>
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android" >
+    &lt;!-- Search, should appear as action button -->
+    &lt;item android:id="@+id/action_search"
+          android:icon="@drawable/ic_action_search"
+          android:title="@string/action_search"
+          android:showAsAction="ifRoom" /&gt;
+    &lt;!-- Settings, should always be in the overflow -->
+    &lt;item android:id="@+id/action_settings"
+          android:title="@string/action_settings"
+          android:showAsAction="never" /&gt;
+&lt;/menu&gt;
+</pre>
+
+<div class="sidebox">
+<h3>Download action bar icons</h3>
+<p>To best match the Android <a
+href="{@docRoot}design/style/iconography.html#action-bar">iconography</a> guidelines, you should
+use icons provided in the
+<a href="{@docRoot}design/downloads/index.html#action-bar-icon-pack">Action Bar Icon Pack</a>.</p>
+</div>
+
+<p>This declares that the Search action should appear as an action button when room
+is available in the action bar, but the
+Settings action should always appear in the overflow. (By default, all actions appear in the
+overflow, but it's good practice to explicitly declare your design intentions for each action.)
+
+<p>However, <strong>if your app is using the Support Library</strong> for compatibility on versions
+as low as Android 2.1, the {@code showAsAction} attribute is not available from
+the {@code android:} namespace. Instead this attribute is provided by the Support Library
+and you must define your own XML namespace and use that namespace as the attribute prefix.
+(A custom XML namespace should be based on your app name, but it can be any
+name you want and is only accessible within the scope of the file in which you declare it.)
+For example:</p>
+
+<p class="code-caption">res/menu/main_activity_actions.xml</p>
+<pre>
+&lt;menu xmlns:android="http://schemas.android.com/apk/res/android"
+      <strong>xmlns:yourapp="http://schemas.android.com/apk/res-auto"</strong> >
+    &lt;!-- Search, should appear as action button -->
+    &lt;item android:id="@+id/action_search"
+          android:icon="@drawable/ic_action_search"
+          android:title="@string/action_search"
+          <strong>yourapp:showAsAction="ifRoom"</strong>  /&gt;
+    ...
+&lt;/menu&gt;
+</pre>
+
+
+
+<h2 id="AddActions">Add the Actions to the Action Bar</h2>
+
+<p>To place the menu items into the action bar, implement the
+{@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} callback
+method in your activity to inflate the menu resource into the given {@link android.view.Menu}
+object. For example:</p>
+
+<pre>
+&#64;Override
+public boolean onCreateOptionsMenu(Menu menu) {
+    // Inflate the menu items for use in the action bar
+    MenuInflater inflater = getMenuInflater();
+    inflater.inflate(R.menu.main_activity_actions, menu);
+    return super.onCreateOptionsMenu(menu);
+}
+</pre>
+
+
+
+<h2 id="Respond">Respond to Action Buttons</h2>
+
+<p>When the user presses one of the action buttons or another item in the action overflow,
+the system calls your activity's {@link android.app.Activity#onOptionsItemSelected
+onOptionsItemSelected()} callback method. In your implementation of this method,
+call {@link android.view.MenuItem#getItemId getItemId()} on the given {@link android.view.MenuItem} to
+determine which item was pressed&mdash;the returned ID matches the value you declared in the
+corresponding {@code &lt;item>} element's {@code android:id} attribute.</p>
+
+<pre>
+&#64;Override
+public boolean onOptionsItemSelected(MenuItem item) {
+    // Handle presses on the action bar items
+    switch (item.getItemId()) {
+        case R.id.action_search:
+            openSearch();
+            return true;
+        case R.id.action_settings:
+            openSettings();
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+    }
+}
+</pre>
+
+
+
+<h2 id="UpNav">Add Up Button for Low-level Activities</h2>
+
+<div class="figure" style="width:240px">
+  <img src="{@docRoot}images/ui/actionbar-up.png" width="240" alt="">
+  <p class="img-caption"><strong>Figure 4.</strong> The <em>Up</em> button in Gmail.</p>
+</div>
+
+<p>All screens in your app that are not the main entrance to your app
+(activities that are not the "home" screen) should
+offer the user a way to navigate to the logical parent screen in the app's hierarchy by pressing
+the <em>Up</em> button in the action bar.</p>
+
+<p>When running on Android 4.1 (API level 16) or higher, or when using {@link
+android.support.v7.app.ActionBarActivity} from the Support Library, performing <em>Up</em>
+navigation simply requires that you declare the parent activity in the manifest file and enable
+the <em>Up</em> button for the action bar.</p>
+
+<p>For example, here's how you can declare an activity's parent in the manifest:</p>
+
+<pre>
+&lt;application ... >
+    ...
+    &lt;!-- The main/home activity (it has no parent activity) -->
+    &lt;activity
+        android:name="com.example.myfirstapp.MainActivity" ...>
+        ...
+    &lt;/activity>
+    &lt;!-- A child of the main activity -->
+    &lt;activity
+        android:name="com.example.myfirstapp.DisplayMessageActivity"
+        android:label="@string/title_activity_display_message"
+        android:parentActivityName="com.example.myfirstapp.MainActivity" >
+        &lt;!-- Parent activity meta-data to support 4.0 and lower -->
+        &lt;meta-data
+            android:name="android.support.PARENT_ACTIVITY"
+            android:value="com.example.myfirstapp.MainActivity" />
+    &lt;/activity>
+&lt;/application>
+</pre>
+
+  <p>Then enable the app icon as the <em>Up</em> button by calling
+{@link android.app.ActionBar#setDisplayHomeAsUpEnabled setDisplayHomeAsUpEnabled()}:</p>
+
+<pre>
+{@literal @}Override
+public void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    setContentView(R.layout.activity_displaymessage);
+
+    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+    // If your minSdkVersion is 11 or higher, instead use:
+    // getActionBar().setDisplayHomeAsUpEnabled(true);
+}
+</pre>
+
+<p>Because the system now knows {@code MainActivity} is the parent activity for
+{@code DisplayMessageActivity}, when the user presses the
+<em>Up</em> button, the system navigates to
+the parent activity as appropriate&mdash;you <strong>do not</strong> need to handle the
+<em>Up</em> button's event.</p>
+
+<p>For more information about up navigation, see
+<a href="{@docRoot}training/implementing-navigation/ancestral.html">Providing Up
+  Navigation</a>.
\ No newline at end of file
diff --git a/docs/html/training/basics/actionbar/index.jd b/docs/html/training/basics/actionbar/index.jd
new file mode 100644
index 0000000..f0de758
--- /dev/null
+++ b/docs/html/training/basics/actionbar/index.jd
@@ -0,0 +1,68 @@
+page.title=Adding the Action Bar
+page.tags="actionbar"
+
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+  <li>Android 2.1 or higher</li>
+</ul>
+
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
+  <li><a href="{@docRoot}training/implementing-navigation/index.html">Implementing
+  Effective Navigation</a></li>
+</ul>
+
+</div>
+</div>
+
+<a class="notice-designers wide" href="{@docRoot}design/patterns/actionbar.html">
+  <div>
+    <h3>Design Guide</h3>
+    <p>Action Bar</p>
+  </div>
+</a>
+
+<p>The action bar is one of the most important design elements you can implement for your
+app's activities. It provides several user interface features that make your app immediately
+familiar to users by offering consistency between other Android apps. Key functions include:</p>
+
+<ul>
+  <li>A dedicated space for giving your app an identity and indicating the user's location
+  in the app.</li>
+  <li>Access to important actions in a predictable way (such as Search).</li>
+  <li>Support for navigation and view switching (with tabs or drop-down lists).</li>
+</ul>
+
+<img src="{@docRoot}images/training/basics/actionbar-actions.png" height="100" alt="">
+
+<p>This training class offers a quick guide to the action bar's basics. For more information
+about action bar's various features, see the
+<a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> guide.</p>
+
+
+<h2>Lessons</h2>
+
+<dl>
+  <dt><b><a href="setting-up.html">Setting Up the Action Bar</a></b></dt>
+  <dd>Learn how to add a basic action bar to your activity, whether your app
+  supports only Android 3.0 and higher or also supports versions as low as Android 2.1
+  (by using the Android Support Library).</dd>
+  <dt><b><a href="adding-buttons.html">Adding Action Buttons</a></b></dt>
+  <dd>Learn how to add and respond to user actions in the action bar.</dd>
+  <dt><b><a href="styling.html">Styling the Action Bar</a></b></dt>
+  <dd>Learn how to customize the appearance of your action bar.</dd>
+  <dt><b><a href="overlaying.html">Overlaying the Action Bar</a></b></dt>
+  <dd>Learn how to overlay the action bar in front of your layout, allowing for
+  seamless transitions when hiding the action bar.</dd>
+</dl>
+
diff --git a/docs/html/training/basics/actionbar/overlaying.jd b/docs/html/training/basics/actionbar/overlaying.jd
new file mode 100644
index 0000000..800cd44
--- /dev/null
+++ b/docs/html/training/basics/actionbar/overlaying.jd
@@ -0,0 +1,141 @@
+page.title=Overlaying the Action Bar
+
+trainingnavtop=true
+
+@jd:body
+
+
+<div id="tb-wrapper">
+  <div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#EnableOverlay">Enable Overlay Mode</a>
+    <ol>
+      <li><a href="#Overlay11">For Android 3.0 and higher only</a></li>
+      <li><a href="#Overlay7">For Android 2.1 and higher</a></li>
+    </ol>
+  </li>
+  <li><a href="#TopMargin">Specify Layout Top-margin</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a></li>
+</ul>
+  </div>
+</div>
+
+
+<p>By default, the action bar appears at the top of your activity window,
+slightly reducing the amount of space available for the rest of your activity's layout.
+If, during the course of user interaction, you want to hide and show the action bar, you can do so
+by calling {@link android.app.ActionBar#hide()} and
+{@link android.app.ActionBar#show()} on the {@link android.app.ActionBar}. However,
+this causes your activity to recompute and redraw the layout based on its new size.</p>
+
+
+<div class="figure" style="width:280px">
+  <img src="{@docRoot}images/training/basics/actionbar-overlay@2x.png" width="280" alt="" />
+  <p class="img-caption"><strong>Figure 1.</strong> Gallery's action bar in overlay mode.</p>
+</div>
+
+<p>To avoid resizing your layout when the action bar hides and shows, you can enable <em>overlay
+mode</em> for the action bar. When in overlay mode, your activity layout uses all the space
+available as if the action bar is not there and the system draws the action bar in front of
+your layout. This obscures some of the layout at the top, but now when the action bar hides or
+appears, the system does not need to resize your layout and the transition is seamless.</p>
+
+<p class="note"><strong>Tip:</strong>
+If you want your layout to be partially visible behind the action bar, create a custom
+style for the action bar with a partially transparent background, such as the one shown
+in figure 1. For information about how to define the action bar background, read
+<a href="{@docRoot}training/basics/actionbar/styling.html">Styling the Action Bar</a>.</p>
+
+
+<h2 id="EnableOverlay">Enable Overlay Mode</h2>
+
+<p>To enable overlay mode for the action bar, you need to create a custom theme that
+extends an existing action bar theme and set the {@code android:windowActionBarOverlay} property to
+{@code true}.</p>
+
+
+<h3 id="Overlay11">For Android 3.0 and higher only</h3>
+
+<p>If your
+<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>
+is set to {@code 11} or higher, your custom theme should use
+{@link android.R.style#Theme_Holo Theme.Holo} theme (or one of its descendants) as your parent
+theme. For example:</p>
+
+<pre>
+&lt;resources>
+    &lt;!-- the theme applied to the application or activity -->
+    &lt;style name="CustomActionBarTheme"
+           parent="&#64;android:style/Theme.Holo">
+        &lt;item name="android:windowActionBarOverlay">true&lt;/item>
+    &lt;/style>
+&lt;/resources>
+</pre>
+
+
+<h3 id="Overlay7">For Android 2.1 and higher</h3>
+
+<p>If your app is using the Support Library for compatibility on devices
+running versions lower than Android 3.0, your custom theme should use
+{@link android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} theme
+(or one of its descendants) as your parent theme. For example:</p>
+
+<pre>
+&lt;resources>
+    &lt;!-- the theme applied to the application or activity -->
+    &lt;style name="CustomActionBarTheme"
+           parent="&#64;android:style/Theme.<strong>AppCompat</strong>">
+        &lt;item name="android:windowActionBarOverlay">true&lt;/item>
+
+        &lt;!-- Support library compatibility -->
+        &lt;item name="windowActionBarOverlay">true&lt;/item>
+    &lt;/style>
+&lt;/resources>
+</pre>
+
+<p>Also notice that this theme includes two definitions for the {@code windowActionBarOverlay}
+style: one with the {@code android:} prefix and one without. The one with the {@code android:}
+prefix is for versions of Android that include the style in the platform and the one
+without the prefix is for older versions that read the style from the Support Library.</p>
+
+
+
+
+
+<h2 id="TopMargin">Specify Layout Top-margin</h2>
+
+<p>When the action bar is in overlay mode, it might obscure some of your layout that should
+remain visible. To ensure that such items remain below the action bar at all times,
+add either margin or padding to the top of the view(s)
+using the height specified by {@link android.R.attr#actionBarSize}. For example:</p>
+
+<pre>
+&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="?android:attr/actionBarSize">
+    ...
+&lt;/RelativeLayout>
+</pre>
+
+<p>If you're using the Support Library for the action bar, you need to remove the
+{@code android:} prefix. For example:</p>
+
+<pre>
+&lt;!-- Support library compatibility -->
+&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="?attr/actionBarSize">
+    ...
+&lt;/RelativeLayout>
+</pre>
+
+<p>In this case, the {@code ?attr/actionBarSize} value without the
+prefix works on all versions, including Android 3.0 and higher.</p>
\ No newline at end of file
diff --git a/docs/html/training/basics/actionbar/setting-up.jd b/docs/html/training/basics/actionbar/setting-up.jd
new file mode 100644
index 0000000..158ce92
--- /dev/null
+++ b/docs/html/training/basics/actionbar/setting-up.jd
@@ -0,0 +1,112 @@
+page.title=Setting Up the Action Bar
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+  <div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#ApiLevel11">Support Android 3.0 and Above Only</a></li>
+  <li><a href="#ApiLevel7">Support Android 2.1 and Above</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}tools/support-library/setup.html"
+>Setting Up the Support Library</a></li>
+</ul>
+  </div>
+</div>
+
+
+<p>In its most basic form, the action bar displays the title for the activity
+and the app icon on the left. Even in this simple form, the action bar
+is useful for all activities to inform
+users about where they are and to maintain a consistent identity for your app.</p>
+
+<img src="{@docRoot}images/training/basics/actionbar-basic.png" height="100" alt=""/>
+<p class="img-caption"><strong>Figure 1.</strong> An action bar with the app icon and
+activity title.</a>
+
+<p>Setting up a basic action bar requires that your app use an activity theme that enables
+the action bar. How to request such a theme depends on which version of Android is the
+lowest supported by your app. So this
+lesson is divided into two sections depending on which Android
+version is your lowest supported.</p>
+
+
+<h2 id="ApiLevel11">Support Android 3.0 and Above Only</h2>
+
+<p>Beginning with Android 3.0 (API level 11), the action bar is included in all
+activities that use the {@link android.R.style#Theme_Holo Theme.Holo} theme (or one of its
+descendants), which is the default theme when either the <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> or
+<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>
+attribute is set to <code>"11"</code> or greater.</p>
+
+<p>So to add the action bar to your activities, simply set either attribute to
+{@code 11} or higher. For example:</p>
+
+<pre>
+&lt;manifest ... &gt;
+    &lt;uses-sdk android:minSdkVersion="11" ... /&gt;
+    ...
+&lt;/manifest&gt;
+</pre>
+
+<p class="note"><strong>Note:</strong> If you've created a custom theme, be sure it uses one
+of the {@link android.R.style#Theme_Holo Theme.Holo} themes as its parent. For details,
+see <a href="{@docRoot}training/basics/actionbar/styling.html">Styling the Action Bar</a>.</p>
+
+<p>Now the {@link android.R.style#Theme_Holo Theme.Holo} theme is applied to your app and
+all activities show the action bar. That's it.</p>
+
+
+
+<h2 id="ApiLevel7">Support Android 2.1 and Above</h2>
+
+<p>Adding the action bar when running on versions older than Android 3.0 (down to Android 2.1)
+requires that you include the Android Support Library in your application.</p>
+
+<p>To get started, read the <a href="{@docRoot}tools/support-library/setup.html"
+>Support Library Setup</a> document and set up the <strong>v7 appcompat</strong>
+library (once you've downloaded the library package, follow the instructions for <a
+href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries with
+resources</a>).</p>
+
+<p>Once you have the Support Library integrated with your app project:</p>
+
+<ol>
+  <li>Update your activity so that it extends {@link android.support.v7.app.ActionBarActivity}.
+  For example:
+<pre>
+public class MainActivity extends ActionBarActivity { ... }
+</pre>
+  </li>
+  <li>In your manifest file, update either the <a
+  href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+  &lt;application>}</a> element or individual
+  <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;activity>}</a>
+  elements to use one of the {@link android.support.v7.appcompat.R.style#Theme_AppCompat
+  Theme.AppCompat} themes. For example:
+  <pre>&lt;activity android:theme="@style/Theme.AppCompat.Light" ... ></pre>
+  <p class="note"><strong>Note:</strong> If you've created a custom theme, be sure it uses one
+of the {@link android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} themes as
+its parent. For details, see <a href="{@docRoot}training/basics/actionbar/styling.html">Styling
+the Action Bar</a>.</p>
+  </li>
+</ol>
+
+<p>Now your activity includes the action bar when running on Android 2.1 (API level 7) or higher.
+</p>
+
+<p>Remember to properly set your app's API level support in the manifest:</p>
+<pre>
+&lt;manifest ... &gt;
+    &lt;uses-sdk android:minSdkVersion="7"  android:targetSdkVersion="18" /&gt;
+    ...
+&lt;/manifest&gt;
+</pre>
\ No newline at end of file
diff --git a/docs/html/training/basics/actionbar/styling.jd b/docs/html/training/basics/actionbar/styling.jd
new file mode 100644
index 0000000..a1cc10c
--- /dev/null
+++ b/docs/html/training/basics/actionbar/styling.jd
@@ -0,0 +1,448 @@
+page.title=Styling the Action Bar
+
+trainingnavtop=true
+
+@jd:body
+
+
+<div id="tb-wrapper">
+  <div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#AndroidThemes">Use an Android Theme</a></li>
+  <li><a href="#CustomBackground">Customize the Background</a></li>
+  <li><a href="#CustomText">Customize the Text Color</a></li>
+  <li><a href="#CustomTabs">Customize the Tab Indicator</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a></li>
+  <li><a class="external-link" target="_blank"
+  href="http://jgilfelt.github.io/android-actionbarstylegenerator/">Android Action Bar Style
+  Generator</a></li>
+</ul>
+
+  </div>
+</div>
+
+
+
+<p>The action bar provides your users a familiar and predictable way to perform
+actions and navigate your app, but that doesn't mean it needs to look exactly the
+same as it does in other apps. If you want to style the action bar to better fit your product
+brand, you can easily do so using Android's <a href="{@docRoot}guide/topics/ui/themes.html">style
+and theme</a> resources.</p>
+
+<p>Android includes a few built-in activity themes that include "dark" or "light" action bar
+styles. You can also extend these themes to further customize the look for your action bar.</p>
+
+<p class="note" style="clear:left"><strong>Note:</strong> If you are using the Support Library APIs
+for the action bar, then you must use (or override) the {@link
+android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} family of styles (rather
+than the {@link android.R.style#Theme_Holo Theme.Holo} family, available in API level 11 and
+higher). In doing so, each style property that you declare must be declared twice: once using
+the platform's style properties (the
+{@link android.R.attr android:} properties) and once using the
+style properties included in the Support Library (the {@link android.support.v7.appcompat.R.attr
+appcompat.R.attr} properties&mdash;the context for these properties is actually
+<em>your app</em>). See the examples below for details.</p>
+
+
+
+<h2 id="AndroidThemes">Use an Android Theme</h2>
+
+<div class="figure" style="width:340px">
+  <img src="{@docRoot}images/training/basics/actionbar-theme-dark@2x.png" width="340" alt="" />
+</div>
+
+<div class="figure" style="width:340px">
+  <img src="{@docRoot}images/training/basics/actionbar-theme-light-solid@2x.png" width="340" alt="" />
+</div>
+
+<p>Android includes two baseline activity themes that dictate the color for the action bar:
+</p>
+<ul>
+  <li>{@link android.R.style#Theme_Holo Theme.Holo} for a "dark" theme.
+  </li>
+  <li>{@link android.R.style#Theme_Holo_Light Theme.Holo.Light} for a "light" theme.
+  </li>
+</ul>
+
+<p>You can apply these themes to your entire app or to individual activities by
+declaring them in your manifest file with the {@code android:theme} attribute
+for the <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+&lt;application>}</a> element or individual
+<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;activity>}</a>
+elements.</p>
+
+<p>For example:</p>
+<pre>
+&lt;application android:theme="@android:style/Theme.Holo.Light" ... />
+</pre>
+
+<div class="figure" style="width:340px">
+  <img src="{@docRoot}images/training/basics/actionbar-theme-light-darkactionbar@2x.png" width="340" alt="" />
+</div>
+
+<p>You can also use a dark action bar while the rest of the activity uses the light
+color scheme by declaring the {@link android.R.style#Theme_Holo_Light_DarkActionBar
+Theme.Holo.Light.DarkActionBar} theme.</p>
+
+<p>When using the Support Library, you must instead use the
+{@link android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} themes:</p>
+<ul>
+  <li>{@link android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} for the
+  "dark" theme.</li>
+  <li>{@link android.support.v7.appcompat.R.style#Theme_AppCompat_Light Theme.AppCompat.Light}
+  for the "light" theme.</li>
+  <li>{@link android.support.v7.appcompat.R.style#Theme_AppCompat_Light_DarkActionBar
+Theme.AppCompat.Light.DarkActionBar} for the light theme with a dark action bar.
+</ul>
+
+<p>Be sure that you use action bar icons that properly contrast with the color of your action
+bar. To help you, the <a href="{@docRoot}design/downloads/index.html#action-bar-icon-pack">Action
+Bar Icon Pack</a> includes standard action icons for use with both the Holo light and Holo dark
+action bar.</p>
+
+
+
+
+
+<h2 id="CustomBackground">Customize the Background</h2>
+
+<div class="figure" style="width:340px">
+  <img src="{@docRoot}images/training/basics/actionbar-theme-custom@2x.png" width="340" alt="" />
+</div>
+
+<p>To change the action bar background, create a custom theme for your activity that overrides the
+{@link android.R.attr#actionBarStyle} property. This property points to another style
+in which you can override the {@link android.R.attr#background} property to specify
+a drawable resource for the action bar background.</p>
+
+<p>If your app uses <a href="{@docRoot}guide/topics/ui/actionbar.html#Tabs">navigation tabs</a>
+or the <a href="{@docRoot}guide/topics/ui/actionbar.html#SplitBar">split
+action bar</a>, then you can also specify the background for these bars using
+the {@link android.R.attr#backgroundStacked} and
+{@link android.R.attr#backgroundSplit} properties, respectively.</p>
+
+<p class="caution"><strong>Caution:</strong> It's important that you declare an appropriate
+parent theme from which your custom theme and style inherit their styles. Without a parent
+style, your action bar will be without many style properties unless you explicitly declare
+them yourself.</p>
+
+
+<h3 id="CustomBackground11">For Android 3.0 and higher only</h3>
+
+<p>When supporting Android 3.0 and higher only, you can define the action bar's
+background like this:</p>
+
+<p class="code-caption">res/values/themes.xml</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;!-- the theme applied to the application or activity -->
+    &lt;style name="CustomActionBarTheme"
+           parent="&#64;style/Theme.Holo.Light.DarkActionBar">
+        &lt;item name="android:actionBarStyle">&#64;style/MyActionBar&lt;/item>
+    &lt;style>
+
+    &lt;!-- ActionBar styles -->
+    &lt;style name="MyActionBar"
+           parent="&#64;style/Widget.Holo.Light.ActionBar.Solid.Inverse">
+        &lt;item name="android:background">&#64;drawable/actionbar_background&lt;/item>
+    &lt;style>
+&lt;/resources>
+</pre>
+
+<p>Then apply your theme to your entire app or individual activities:</p>
+<pre>
+&lt;application android:theme="&#64;style/CustomActionBarTheme" ... />
+</pre>
+
+
+
+<h3 id="CustomBackground7">For Android 2.1 and higher</h3>
+
+<p>When using the Support Library, the same theme as above must instead look like this:</p>
+
+<p class="code-caption">res/values/themes.xml</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;!-- the theme applied to the application or activity -->
+    &lt;style name="CustomActionBarTheme"
+           parent="&#64;style/Theme.<strong>AppCompat</strong>.Light.DarkActionBar">
+        &lt;item name="android:actionBarStyle">&#64;style/MyActionBar&lt;/item>
+
+        &lt;!-- Support library compatibility -->
+        &lt;item name="actionBarStyle">&#64;style/MyActionBar&lt;/item>
+    &lt;style>
+
+    &lt;!-- ActionBar styles -->
+    &lt;style name="MyActionBar"
+           parent="&#64;style/Widget.<strong>AppCompat</strong>.Light.ActionBar.Solid.Inverse">
+        &lt;item name="android:background">&#64;drawable/actionbar_background&lt;/item>
+
+        &lt;!-- Support library compatibility -->
+        &lt;item name="background">&#64;drawable/actionbar_background&lt;/item>
+    &lt;style>
+&lt;/resources>
+</pre>
+
+<p>Then apply your theme to your entire app or individual activities:</p>
+<pre>
+&lt;application android:theme="&#64;style/CustomActionBarTheme" ... />
+</pre>
+
+
+
+
+
+
+
+<h2 id="CustomText">Customize the Text Color</h2>
+
+<p>To modify the color of text in the action bar, you need to override separate properties
+for each text element:</p>
+<ul>
+  <li>Action bar title: Create a custom style that specifies the {@code textColor} property and
+  specify that style for the {@link android.R.attr#titleTextStyle} property in your custom
+  {@link android.R.attr#actionBarStyle}.
+    <p class="note"><strong>Note:</strong>
+    The custom style applied to {@link android.R.attr#titleTextStyle} should use
+    {@link android.R.style#TextAppearance_Holo_Widget_ActionBar_Title
+    TextAppearance.Holo.Widget.ActionBar.Title} as the parent style.</p>
+  </li>
+  <li>Action bar tabs: Override {@link android.R.attr#actionBarTabTextStyle} in your
+  activity theme.</li>
+  <li>Action buttons: Override {@link android.R.attr#actionMenuTextColor} in your
+  activity theme.</li>
+</ul>
+
+
+<h3 id="CustomText11">For Android 3.0 and higher only</h3>
+
+<p>When supporting Android 3.0 and higher only, your style XML file might look like this:</p>
+
+<p class="code-caption">res/values/themes.xml</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;!-- the theme applied to the application or activity -->
+    &lt;style name="CustomActionBarTheme"
+           parent="&#64;style/Theme.Holo">
+        &lt;item name="android:actionBarStyle">&#64;style/MyActionBar&lt;/item>
+        &lt;item name="android:actionBarTabTextStyle">&#64;style/MyActionBarTabText&lt;/item>
+        &lt;item name="android:actionMenuTextColor">&#64;color/actionbar_text&lt;/item>
+    &lt;style>
+
+    &lt;!-- ActionBar styles -->
+    &lt;style name="MyActionBar"
+           parent="&#64;style/Widget.Holo.ActionBar">
+        &lt;item name="android:titleTextStyle">&#64;style/MyActionBarTitleText&lt;/item>
+    &lt;style>
+
+    &lt;!-- ActionBar title text -->
+    &lt;style name="MyActionBarTitleText"
+           parent="&#64;style/TextAppearance.Holo.Widget.ActionBar.Title">
+        &lt;item name="android:textColor">&#64;color/actionbar_text&lt;/item>
+    &lt;style>
+
+    &lt;!-- ActionBar tabs text styles -->
+    &lt;style name="MyActionBarTabText"
+           parent="&#64;style/Widget.Holo.ActionBar.TabText">
+        &lt;item name="android:textColor">&#64;color/actionbar_text&lt;/item>
+    &lt;style>
+&lt;/resources>
+</pre>
+
+
+
+
+<h3 id="CustomText7">For Android 2.1 and higher</h3>
+
+<p>When using the Support Library, your style XML file might look like this:</p>
+
+<p class="code-caption">res/values/themes.xml</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;!-- the theme applied to the application or activity -->
+    &lt;style name="CustomActionBarTheme"
+           parent="&#64;style/Theme.<strong>AppCompat</strong>">
+        &lt;item name="android:actionBarStyle">&#64;style/MyActionBar&lt;/item>
+        &lt;item name="android:actionBarTabTextStyle">&#64;style/MyActionBarTabText&lt;/item>
+        &lt;item name="android:actionMenuTextColor">&#64;color/actionbar_text&lt;/item>
+
+        &lt;!-- Support library compatibility -->
+        &lt;item name="actionBarStyle">&#64;style/MyActionBar&lt;/item>
+        &lt;item name="actionBarTabTextStyle">&#64;style/MyActionBarTabText&lt;/item>
+        &lt;item name="actionMenuTextColor">&#64;color/actionbar_text&lt;/item>
+    &lt;style>
+
+    &lt;!-- ActionBar styles -->
+    &lt;style name="MyActionBar"
+           parent="&#64;style/Widget.<strong>AppCompat</strong>.ActionBar">
+        &lt;item name="android:titleTextStyle">&#64;style/MyActionBarTitleText&lt;/item>
+
+        &lt;!-- Support library compatibility -->
+        &lt;item name="titleTextStyle">&#64;style/MyActionBarTitleText&lt;/item>
+    &lt;style>
+
+    &lt;!-- ActionBar title text -->
+    &lt;style name="MyActionBarTitleText"
+           parent="&#64;style/TextAppearance.<strong>AppCompat</strong>.Widget.ActionBar.Title">
+        &lt;item name="android:textColor">&#64;color/actionbar_text&lt;/item>
+        &lt;!-- The textColor property is backward compatible with the Support Library -->
+    &lt;style>
+
+    &lt;!-- ActionBar tabs text -->
+    &lt;style name="MyActionBarTabText"
+           parent="&#64;style/Widget.<strong>AppCompat</strong>.ActionBar.TabText">
+        &lt;item name="android:textColor">&#64;color/actionbar_text&lt;/item>
+        &lt;!-- The textColor property is backward compatible with the Support Library -->
+    &lt;style>
+&lt;/resources>
+</pre>
+
+
+
+
+
+
+<h2 id="CustomTabs">Customize the Tab Indicator</h2>
+
+<div class="figure" style="width:340px">
+  <img src="{@docRoot}images/training/basics/actionbar-theme-custom-tabs@2x.png" width="340" alt="" />
+</div>
+
+<p>To change the indicator used for the <a
+href="{@docRoot}guide/topics/ui/actionbar.html#Tabs">navigation tabs</a>,
+create an activity theme that overrides the
+{@link android.R.attr#actionBarTabStyle} property. This property points to another style
+resource in which you override the {@link android.R.attr#background} property that should specify
+a state-list drawable.</p>
+
+<p class="note"><strong>Note:</strong> A state-list drawable is important so that the tab currently
+selected indicates its state with a background different than the other tabs. For more information
+about how to create a drawable resource that handles multiple button states, read the
+<a href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">State List</a>
+documentation.</p>
+
+<p>For example, here's a state-list drawable that declares a specific background image
+for several different states of an action bar tab:</p>
+
+<p class="code-caption">res/drawable/actionbar_tab_indicator.xml</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+&lt;!-- STATES WHEN BUTTON IS NOT PRESSED -->
+
+    &lt;!-- Non focused states -->
+    &lt;item android:state_focused="false" android:state_selected="false"
+          android:state_pressed="false"
+          android:drawable="&#64;drawable/tab_unselected" />
+    &lt;item android:state_focused="false" android:state_selected="true"
+          android:state_pressed="false"
+          android:drawable="&#64;drawable/tab_selected" />
+
+    &lt;!-- Focused states (such as when focused with a d-pad or mouse hover) -->
+    &lt;item android:state_focused="true" android:state_selected="false"
+          android:state_pressed="false"
+          android:drawable="&#64;drawable/tab_unselected_focused" />
+    &lt;item android:state_focused="true" android:state_selected="true"
+          android:state_pressed="false"
+          android:drawable="&#64;drawable/tab_selected_focused" />
+
+
+&lt;!-- STATES WHEN BUTTON IS PRESSED -->
+
+    &lt;!-- Non focused states -->
+    &lt;item android:state_focused="false" android:state_selected="false"
+          android:state_pressed="true"
+          android:drawable="&#64;drawable/tab_unselected_pressed" />
+    &lt;item android:state_focused="false" android:state_selected="true"
+        android:state_pressed="true"
+        android:drawable="&#64;drawable/tab_selected_pressed" />
+
+    &lt;!-- Focused states (such as when focused with a d-pad or mouse hover) -->
+    &lt;item android:state_focused="true" android:state_selected="false"
+          android:state_pressed="true"
+          android:drawable="&#64;drawable/tab_unselected_pressed" />
+    &lt;item android:state_focused="true" android:state_selected="true"
+          android:state_pressed="true"
+          android:drawable="&#64;drawable/tab_selected_pressed" />
+&lt;/selector>
+</pre>
+
+
+
+<h3 id="CustomTabs11">For Android 3.0 and higher only</h3>
+
+<p>When supporting Android 3.0 and higher only, your style XML file might look like this:</p>
+
+<p class="code-caption">res/values/themes.xml</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;!-- the theme applied to the application or activity -->
+    &lt;style name="CustomActionBarTheme"
+           parent="&#64;style/Theme.Holo">
+        &lt;item name="android:actionBarTabStyle">&#64;style/MyActionBarTabs&lt;/item>
+    &lt;style>
+
+    &lt;!-- ActionBar tabs styles -->
+    &lt;style name="MyActionBarTabs"
+           parent="&#64;style/Widget.Holo.ActionBar.TabView">
+        &lt;!-- tab indicator -->
+        &lt;item name="android:background">&#64;drawable/actionbar_tab_indicator&lt;/item>
+    &lt;style>
+&lt;/resources>
+</pre>
+
+
+
+<h3 id="CustomTabs7">For Android 2.1 and higher</h3>
+
+<p>When using the Support Library, your style XML file might look like this:</p>
+
+<p class="code-caption">res/values/themes.xml</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;!-- the theme applied to the application or activity -->
+    &lt;style name="CustomActionBarTheme"
+           parent="&#64;style/Theme.<strong>AppCompat</strong>">
+        &lt;item name="android:actionBarTabStyle">&#64;style/MyActionBarTabs&lt;/item>
+
+        &lt;!-- Support library compatibility -->
+        &lt;item name="actionBarTabStyle">&#64;style/MyActionBarTabs&lt;/item>
+    &lt;style>
+
+    &lt;!-- ActionBar tabs styles -->
+    &lt;style name="MyActionBarTabs"
+           parent="&#64;style/Widget.<strong>AppCompat</strong>.ActionBar.TabView">
+        &lt;!-- tab indicator -->
+        &lt;item name="android:background">&#64;drawable/actionbar_tab_indicator&lt;/item>
+
+        &lt;!-- Support library compatibility -->
+        &lt;item name="background">&#64;drawable/actionbar_tab_indicator&lt;/item>
+    &lt;style>
+&lt;/resources>
+</pre>
+
+<div class="note"><p><strong>More resources</strong></p>
+<ul>
+  <li>See more style properties for the action bar are listed in the <a
+  href="{@docRoot}guide/topics/ui/actionbar.html#Style">Action Bar</a> guide.</li>
+  <li>Learn more about how themes work in the <a
+  href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a> guide.</li>
+  <li>For even more complete styling for the action bar,
+try the <a class="external-link" target="_blank"
+  href="www://http.actionbarstylegenerator.com">Android Action Bar Style
+  Generator</a>.</li>
+</ul>
+</div>
\ No newline at end of file
diff --git a/docs/html/training/basics/fragments/creating.jd b/docs/html/training/basics/fragments/creating.jd
index b5df4e1..377adfc 100644
--- a/docs/html/training/basics/fragments/creating.jd
+++ b/docs/html/training/basics/fragments/creating.jd
@@ -6,7 +6,7 @@
 
 <div id="tb-wrapper">
   <div id="tb">
-    
+
     <h2>This lesson teaches you to</h2>
 <ol>
   <li><a href="#Create">Create a Fragment Class</a></li>
@@ -19,7 +19,7 @@
     </ul>
 
 <h2>Try it out</h2>
-    
+
 <div class="download-box">
  <a href="http://developer.android.com/shareables/training/FragmentBasics.zip"
 class="button">Download the sample</a>
@@ -32,21 +32,30 @@
 <p>You can think of a fragment as a modular section of an activity, which has its own lifecycle,
 receives its own input events, and which you can add or remove while the activity is running (sort
 of like a "sub activity" that you can reuse in different activities). This lesson shows how to
-extend the {@link android.support.v4.app.Fragment} class using the Support Library so your app
-remains compatible with devices running system versions as old as Android 1.6.</p>
+extend the {@link android.support.v4.app.Fragment} class using the <a
+href="{@docRoot}tools/support-library/index.html">Support Library</a> so your app
+remains compatible with devices running system versions as low as Android 1.6.</p>
 
-<p class="note"><strong>Note:</strong> If you decide for other reasons that the minimum
+<p class="note"><strong>Note:</strong> If you decide that the minimum
 API level your app requires is 11 or higher, you don't need to use the Support
 Library and can instead use the framework's built in {@link android.app.Fragment} class and related
 APIs. Just be aware that this lesson is focused on using the APIs from the Support Library, which
 use a specific package signature and sometimes slightly different API names than the versions
 included in the platform.</p>
 
+<p>Before you begin this lesson, you must set up your Android project to use the Support Library.
+If you have not used the Support Library before, set up your project to use the <strong>v4</strong>
+library by following the <a href="{@docRoot}tools/support-library/setup.html">Support Library
+Setup</a> document. However, you can also include the <a href=
+"{@docRoot}guide/topics/ui/actionbar.html">action bar</a> in your activities by instead using the
+<strong>v7 appcompat</strong> library, which is compatible with Android 2.1 (API level 7)
+and also includes the {@link android.support.v4.app.Fragment} APIs.</p>
+
 
 
 <h2 id="Create">Create a Fragment Class</h2>
 
-<p>To create a fragment, extend the {@link android.support.v4.app.Fragment} class, then override 
+<p>To create a fragment, extend the {@link android.support.v4.app.Fragment} class, then override
 key lifecycle methods to insert your app logic, similar to the way you would with an {@link
 android.app.Activity} class.</p>
 
@@ -63,7 +72,7 @@
 
 public class ArticleFragment extends Fragment {
     &#64;Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
         Bundle savedInstanceState) {
         // Inflate the layout for this fragment
         return inflater.inflate(R.layout.article_view, container, false);
@@ -82,7 +91,7 @@
 
 
 
-<h2 id="AddInLayout">Add a Fragment to an Activity using XML</h2> 
+<h2 id="AddInLayout">Add a Fragment to an Activity using XML</h2>
 
 <p>While fragments are reusable, modular UI components, each instance of a {@link
 android.support.v4.app.Fragment} class must be associated with a parent {@link
@@ -98,7 +107,7 @@
 screen is considered "large" (specified by the <code>large</code> qualifier in the directory
 name).</p>
 
-<p><code>res/layout-large/news_articles.xml:</code></p>
+<p class="code-caption">res/layout-large/news_articles.xml</p>
 <pre>
 &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
@@ -120,11 +129,11 @@
 &lt;/LinearLayout>
 </pre>
 
-<p class="note"><strong>Tip:</strong> For more information about creating layouts for different
+<p class="note"><strong>Tip:</strong> For more about creating layouts for different
 screen sizes, read <a href="{@docRoot}training/multiscreen/screensizes.html">Supporting Different
 Screen Sizes</a>.</p>
 
-<p>Here's how an activity applies this layout:</p>
+<p>Then apply the layout to your activity:</p>
 
 <pre>
 import android.os.Bundle;
@@ -139,6 +148,12 @@
 }
 </pre>
 
+<p>If you're using the <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
+appcompat library</a>, your activity should instead extend {@link
+android.support.v7.app.ActionBarActivity}, which is a subclass of {@link
+android.support.v4.app.FragmentActivity} (for more information,
+read <a href="{@docRoot}training/basics/actionbar/index.html">Adding the Action Bar</a>).</p>
+
 
 <p class="note"><strong>Note:</strong> When you add a fragment to an activity layout by defining
 the fragment in the layout XML file, you <em>cannot</em> remove the fragment at runtime. If you plan
diff --git a/docs/html/training/basics/fragments/index.jd b/docs/html/training/basics/fragments/index.jd
index 1b82f2c..987decf 100644
--- a/docs/html/training/basics/fragments/index.jd
+++ b/docs/html/training/basics/fragments/index.jd
@@ -57,9 +57,6 @@
 <h2>Lessons</h2>
  
 <dl>
-  <dt><b><a href="support-lib.html">Using the Android Support Library</a></b></dt>
-    <dd>Learn how to use more recent framework APIs in earlier versions of Android by bundling
-the Android Support Library into your app.</dd>
   <dt><b><a href="creating.html">Creating a Fragment</a></b></dt>
     <dd>Learn how to build a fragment and implement basic behaviors within its callback
 methods.</dd>
diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd
index 1646b91..aba3896 100644
--- a/docs/html/training/basics/intents/sending.jd
+++ b/docs/html/training/basics/intents/sending.jd
@@ -240,7 +240,7 @@
 
 // Always use string resources for UI text.
 // This says something like "Share this photo with"
-String title = (String) getResources().getText(R.string.chooser_title);
+String title = getResources().getString(R.string.chooser_title);
 // Create and start the chooser
 Intent chooser = Intent.createChooser(intent, title);
 startActivity(chooser);
diff --git a/docs/html/training/gestures/scroll.jd b/docs/html/training/gestures/scroll.jd
index 3e3aa14..09fcc4e 100644
--- a/docs/html/training/gestures/scroll.jd
+++ b/docs/html/training/gestures/scroll.jd
@@ -95,7 +95,7 @@
 finger across the touch screen. Simple dragging is often implemented by overriding 
 {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} in 
 {@link android.view.GestureDetector.OnGestureListener}. For more discussion of dragging, see 
-<a href="dragging.jd">Dragging and Scaling</a>.</li>
+<a href="dragging.html">Dragging and Scaling</a>.</li>
 
     <li><strong>Flinging</strong> is the type of scrolling that occurs when a user 
 drags and lifts her finger quickly. After the user lifts her finger, you generally 
diff --git a/docs/html/training/implementing-navigation/index.jd b/docs/html/training/implementing-navigation/index.jd
index 5b65716..24c98f2 100644
--- a/docs/html/training/implementing-navigation/index.jd
+++ b/docs/html/training/implementing-navigation/index.jd
@@ -47,9 +47,9 @@
 
 <p class="note"><strong>Note:</strong> Several elements of this class require the
 <a href="{@docRoot}tools/support-library/index.html">Support Library</a> APIs.
-If you have not used the Support Library before, follow the lesson about <a
-href="{@docRoot}training/basics/fragments/support-lib.html">Using the Support Library</a>
-to get your project set up.</p>
+If you have not used the Support Library before, follow the instructions
+in the <a href="{@docRoot}tools/support-library/setup.html">Support Library Setup</a>
+document.</p>
 
 
 <h2 id="lessons">Lessons</h2>
diff --git a/docs/html/training/implementing-navigation/lateral.jd b/docs/html/training/implementing-navigation/lateral.jd
index 97e0398..bb9d78c 100644
--- a/docs/html/training/implementing-navigation/lateral.jd
+++ b/docs/html/training/implementing-navigation/lateral.jd
@@ -1,5 +1,5 @@
 page.title=Creating Swipe Views with Tabs
-page.tags="viewpager","horizontal","paging","swipe view"
+page.tags="viewpager","horizontal","paging","swipe view","tabs"
 
 trainingnavtop=true
 
diff --git a/docs/html/training/load-data-background/index.jd b/docs/html/training/load-data-background/index.jd
index 221ae57..29108e8 100644
--- a/docs/html/training/load-data-background/index.jd
+++ b/docs/html/training/load-data-background/index.jd
@@ -54,7 +54,8 @@
 </p>
 <p>
     This class describes how to use a {@link android.support.v4.content.CursorLoader} to run a
-    background query. Examples in this class use the {@link android.support.v4 v4 support library}
+    background query. Examples in this class use the <a
+    href="{@docRoot}tools/support-library/features.html#v4">v4 Support Library</a>
     versions of classes, which support platforms starting with Android 1.6.
 </p>
 <h2>Lessons</h2>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index cb57752..c99fc96 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -39,6 +39,35 @@
 
       <li class="nav-section">
         <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/basics/actionbar/index.html"
+             description=
+             "The action bar is one of the most important design elements you can implement for your
+app's activities. Although first introduced with API level 11, you can use the Support Library to
+include the action bar on devices running Android 2.1 or higher."
+            >Adding the Action Bar</a>
+        </div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/basics/actionbar/setting-up.html">
+            Setting Up the Action Bar
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/basics/actionbar/adding-buttons.html">
+            Adding Action Buttons
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/basics/actionbar/styling.html">
+            Styling the Action Bar
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/basics/actionbar/overlaying.html">
+            Overlaying the Action Bar
+          </a>
+          </li>
+        </ul>
+      </li>
+
+      <li class="nav-section">
+        <div class="nav-section-header">
           <a href="<?cs var:toroot ?>training/basics/activity-lifecycle/index.html"
              description=
              "How Android activities live and die and how to create
@@ -100,10 +129,6 @@
             >Building a Dynamic UI with Fragments</a>
         </div>
         <ul>
-          <li><a href="<?cs var:toroot ?>training/basics/fragments/support-lib.html">
-            Using the Support Library
-          </a>
-          </li>
           <li><a href="<?cs var:toroot ?>training/basics/fragments/creating.html">
             Creating a Fragment
           </a>
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index f74d0ef..a4f75b9 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -28,6 +28,9 @@
     @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
     public final Bitmap mBitmap;
 
+    private TileMode mTileX;
+    private TileMode mTileY;
+
     /**
      * Call this to create a new shader that will draw with a bitmap.
      *
@@ -37,11 +40,23 @@
      */
     public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
         mBitmap = bitmap;
+        mTileX = tileX;
+        mTileY = tileY;
         final int b = bitmap.ni();
         native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt);
         native_shader = nativePostCreate(native_instance, b, tileX.nativeInt, tileY.nativeInt);
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final BitmapShader copy = new BitmapShader(mBitmap, mTileX, mTileY);
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
     private static native int nativeCreate(int native_bitmap, int shaderTileModeX,
             int shaderTileModeY);
     private static native int nativePostCreate(int native_shader, int native_bitmap,
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 6a4e89a..f526d29 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -406,18 +406,18 @@
         sColorNameMap.put("yellow", YELLOW);
         sColorNameMap.put("cyan", CYAN);
         sColorNameMap.put("magenta", MAGENTA);
-        sColorNameMap.put("aqua", 0x00FFFF);
-        sColorNameMap.put("fuchsia", 0xFF00FF);
+        sColorNameMap.put("aqua", 0xFF00FFFF);
+        sColorNameMap.put("fuchsia", 0xFFFF00FF);
         sColorNameMap.put("darkgrey", DKGRAY);
         sColorNameMap.put("grey", GRAY);
         sColorNameMap.put("lightgrey", LTGRAY);
-        sColorNameMap.put("lime", 0x00FF00);
-        sColorNameMap.put("maroon", 0x800000);
-        sColorNameMap.put("navy", 0x000080);
-        sColorNameMap.put("olive", 0x808000);
-        sColorNameMap.put("purple", 0x800080);
-        sColorNameMap.put("silver", 0xC0C0C0);
-        sColorNameMap.put("teal", 0x008080);
+        sColorNameMap.put("lime", 0xFF00FF00);
+        sColorNameMap.put("maroon", 0xFF800000);
+        sColorNameMap.put("navy", 0xFF000080);
+        sColorNameMap.put("olive", 0xFF808000);
+        sColorNameMap.put("purple", 0xFF800080);
+        sColorNameMap.put("silver", 0xFFC0C0C0);
+        sColorNameMap.put("teal", 0xFF008080);
 
     }
 }
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index 241ab17..de0d3d6 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -16,10 +16,22 @@
 
 package android.graphics;
 
-/** A subclass of shader that returns the coposition of two other shaders, combined by
+/** A subclass of shader that returns the composition of two other shaders, combined by
     an {@link android.graphics.Xfermode} subclass.
 */
 public class ComposeShader extends Shader {
+
+    private static final int TYPE_XFERMODE = 1;
+    private static final int TYPE_PORTERDUFFMODE = 2;
+
+    /**
+     * Type of the ComposeShader: can be either TYPE_XFERMODE or TYPE_PORTERDUFFMODE
+     */
+    private int mType;
+
+    private Xfermode mXferMode;
+    private PorterDuff.Mode mPorterDuffMode;
+
     /**
      * Hold onto the shaders to avoid GC.
      */
@@ -37,8 +49,10 @@
                         is null, then SRC_OVER is assumed.
     */
     public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
+        mType = TYPE_XFERMODE;
         mShaderA = shaderA;
         mShaderB = shaderB;
+        mXferMode = mode;
         native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance,
                 (mode != null) ? mode.native_instance : 0);
         if (mode instanceof PorterDuffXfermode) {
@@ -59,14 +73,37 @@
         @param mode     The PorterDuff mode that combines the colors from the two shaders.
     */
     public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
+        mType = TYPE_PORTERDUFFMODE;
         mShaderA = shaderA;
         mShaderB = shaderB;
+        mPorterDuffMode = mode;
         native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance,
                 mode.nativeInt);
         native_shader = nativePostCreate2(native_instance, shaderA.native_shader,
                 shaderB.native_shader, mode.nativeInt);
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final ComposeShader copy;
+        switch (mType) {
+            case TYPE_XFERMODE:
+                copy = new ComposeShader(mShaderA.copy(), mShaderB.copy(), mXferMode);
+                break;
+            case TYPE_PORTERDUFFMODE:
+                copy = new ComposeShader(mShaderA.copy(), mShaderB.copy(), mPorterDuffMode);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "ComposeShader should be created with either Xfermode or PorterDuffMode");
+        }
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
     private static native int nativeCreate1(int native_shaderA, int native_shaderB,
             int native_mode);
     private static native int nativeCreate2(int native_shaderA, int native_shaderB,
diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java
index 96a71e3..54cdcab 100644
--- a/graphics/java/android/graphics/LinearGradient.java
+++ b/graphics/java/android/graphics/LinearGradient.java
@@ -17,6 +17,27 @@
 package android.graphics;
 
 public class LinearGradient extends Shader {
+
+    private static final int TYPE_COLORS_AND_POSITIONS = 1;
+    private static final int TYPE_COLOR_START_AND_COLOR_END = 2;
+
+    /**
+     * Type of the LinearGradient: can be either TYPE_COLORS_AND_POSITIONS or
+     * TYPE_COLOR_START_AND_COLOR_END.
+     */
+    private int mType;
+
+    private float mX0;
+    private float mY0;
+    private float mX1;
+    private float mY1;
+    private int[] mColors;
+    private float[] mPositions;
+    private int mColor0;
+    private int mColor1;
+
+    private TileMode mTileMode;
+
 	/**	Create a shader that draws a linear gradient along a line.
         @param x0           The x-coordinate for the start of the gradient line
         @param y0           The y-coordinate for the start of the gradient line
@@ -36,6 +57,14 @@
         if (positions != null && colors.length != positions.length) {
             throw new IllegalArgumentException("color and position arrays must be of equal length");
         }
+        mType = TYPE_COLORS_AND_POSITIONS;
+        mX0 = x0;
+        mY0 = y0;
+        mX1 = x1;
+        mY1 = y1;
+        mColors = colors;
+        mPositions = positions;
+        mTileMode = tile;
         native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt);
         native_shader = nativePostCreate1(native_instance, x0, y0, x1, y1, colors, positions,
                 tile.nativeInt);
@@ -52,12 +81,42 @@
 	*/
 	public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
             TileMode tile) {
+        mType = TYPE_COLOR_START_AND_COLOR_END;
+        mX0 = x0;
+        mY0 = y0;
+        mX1 = x1;
+        mY1 = y1;
+        mColor0 = color0;
+        mColor1 = color1;
+        mTileMode = tile;
         native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
         native_shader = nativePostCreate2(native_instance, x0, y0, x1, y1, color0, color1,
                 tile.nativeInt);
     }
 
-	private native int nativeCreate1(float x0, float y0, float x1, float y1,
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final LinearGradient copy;
+        switch (mType) {
+            case TYPE_COLORS_AND_POSITIONS:
+                copy = new LinearGradient(mX0, mY0, mX1, mY1, mColors.clone(), mPositions.clone(),
+                        mTileMode);
+                break;
+            case TYPE_COLOR_START_AND_COLOR_END:
+                copy = new LinearGradient(mX0, mY0, mX1, mY1, mColor0, mColor1, mTileMode);
+                break;
+            default:
+                throw new IllegalArgumentException("LinearGradient should be created with either " +
+                        "colors and positions or start color and end color");
+        }
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
+    private native int nativeCreate1(float x0, float y0, float x1, float y1,
             int colors[], float positions[], int tileMode);
 	private native int nativeCreate2(float x0, float y0, float x1, float y1,
             int color0, int color1, int tileMode);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1485d8d..331cf6e 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -105,9 +105,17 @@
     public static final int SUBPIXEL_TEXT_FLAG  = 0x80;
     /** bit mask for the flag enabling device kerning for text */
     public static final int DEV_KERN_TEXT_FLAG  = 0x100;
+    /** @hide bit mask for the flag enabling subpixel glyph rendering for text */
+    public static final int LCD_RENDER_TEXT_FLAG = 0x200;
+    /** bit mask for the flag enabling embedded bitmap strikes for text */
+    public static final int EMBEDDED_BITMAP_TEXT_FLAG = 0x400;
+    /** @hide bit mask for the flag forcing freetype's autohinter on for text */
+    public static final int AUTO_HINTING_TEXT_FLAG = 0x800;
+    /** @hide bit mask for the flag enabling vertical rendering for text */
+    public static final int VERTICAL_TEXT_FLAG = 0x1000;
 
     // we use this when we first create a paint
-    static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG;
+    static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG;
 
     /**
      * Option for {@link #setHinting}: disable hinting.
@@ -421,7 +429,9 @@
         mMaskFilter = paint.mMaskFilter;
         mPathEffect = paint.mPathEffect;
         mRasterizer = paint.mRasterizer;
-        mShader = paint.mShader;
+        if (paint.mShader != null) {
+            mShader = paint.mShader.copy();
+        }
         mTypeface = paint.mTypeface;
         mXfermode = paint.mXfermode;
 
diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java
index 897762c..23244d8 100644
--- a/graphics/java/android/graphics/RadialGradient.java
+++ b/graphics/java/android/graphics/RadialGradient.java
@@ -18,6 +18,25 @@
 
 public class RadialGradient extends Shader {
 
+    private static final int TYPE_COLORS_AND_POSITIONS = 1;
+    private static final int TYPE_COLOR_CENTER_AND_COLOR_EDGE = 2;
+
+    /**
+     * Type of the RadialGradient: can be either TYPE_COLORS_AND_POSITIONS or
+     * TYPE_COLOR_CENTER_AND_COLOR_EDGE.
+     */
+    private int mType;
+
+    private float mX;
+    private float mY;
+    private float mRadius;
+    private int[] mColors;
+    private float[] mPositions;
+    private int mColor0;
+    private int mColor1;
+
+    private TileMode mTileMode;
+
 	/**	Create a shader that draws a radial gradient given the center and radius.
         @param x        The x-coordinate of the center of the radius
         @param y        The y-coordinate of the center of the radius
@@ -39,6 +58,13 @@
         if (positions != null && colors.length != positions.length) {
             throw new IllegalArgumentException("color and position arrays must be of equal length");
         }
+        mType = TYPE_COLORS_AND_POSITIONS;
+        mX = x;
+        mY = y;
+        mRadius = radius;
+        mColors = colors;
+        mPositions = positions;
+        mTileMode = tile;
         native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt);
         native_shader = nativePostCreate1(native_instance, x, y, radius, colors, positions,
                 tile.nativeInt);
@@ -57,12 +83,41 @@
         if (radius <= 0) {
             throw new IllegalArgumentException("radius must be > 0");
         }
+        mType = TYPE_COLOR_CENTER_AND_COLOR_EDGE;
+        mX = x;
+        mY = y;
+        mRadius = radius;
+        mColor0 = color0;
+        mColor1 = color1;
+        mTileMode = tile;
         native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt);
         native_shader = nativePostCreate2(native_instance, x, y, radius, color0, color1,
                 tile.nativeInt);
     }
 
-	private static native int nativeCreate1(float x, float y, float radius,
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final RadialGradient copy;
+        switch (mType) {
+            case TYPE_COLORS_AND_POSITIONS:
+                copy = new RadialGradient(mX, mY, mRadius, mColors.clone(), mPositions.clone(),
+                        mTileMode);
+                break;
+            case TYPE_COLOR_CENTER_AND_COLOR_EDGE:
+                copy = new RadialGradient(mX, mY, mRadius, mColor0, mColor1, mTileMode);
+                break;
+            default:
+                throw new IllegalArgumentException("RadialGradient should be created with either " +
+                        "colors and positions or center color and edge color");
+        }
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
+    private static native int nativeCreate1(float x, float y, float radius,
             int colors[], float positions[], int tileMode);
 	private static native int nativeCreate2(float x, float y, float radius,
             int color0, int color1, int tileMode);
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 43758e7..afc68d8 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -90,6 +90,28 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    protected Shader copy() {
+        final Shader copy = new Shader();
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
+    /**
+     * @hide
+     */
+    protected void copyLocalMatrix(Shader dest) {
+        if (mLocalMatrix != null) {
+            final Matrix lm = new Matrix();
+            getLocalMatrix(lm);
+            dest.setLocalMatrix(lm);
+        } else {
+            dest.setLocalMatrix(null);
+        }
+    }
+
     private static native void nativeDestructor(int native_shader, int native_skiaShader);
     private static native void nativeSetLocalMatrix(int native_shader,
             int native_skiaShader, int matrix_instance);
diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java
index 2afdd4d..3010927 100644
--- a/graphics/java/android/graphics/SweepGradient.java
+++ b/graphics/java/android/graphics/SweepGradient.java
@@ -18,6 +18,22 @@
 
 public class SweepGradient extends Shader {
 
+    private static final int TYPE_COLORS_AND_POSITIONS = 1;
+    private static final int TYPE_COLOR_START_AND_COLOR_END = 2;
+
+    /**
+     * Type of the LinearGradient: can be either TYPE_COLORS_AND_POSITIONS or
+     * TYPE_COLOR_START_AND_COLOR_END.
+     */
+    private int mType;
+
+    private float mCx;
+    private float mCy;
+    private int[] mColors;
+    private float[] mPositions;
+    private int mColor0;
+    private int mColor1;
+
     /**
      * A subclass of Shader that draws a sweep gradient around a center point.
      *
@@ -41,6 +57,11 @@
             throw new IllegalArgumentException(
                         "color and position arrays must be of equal length");
         }
+        mType = TYPE_COLORS_AND_POSITIONS;
+        mCx = cx;
+        mCy = cy;
+        mColors = colors;
+        mPositions = positions;
         native_instance = nativeCreate1(cx, cy, colors, positions);
         native_shader = nativePostCreate1(native_instance, cx, cy, colors, positions);
     }
@@ -54,10 +75,36 @@
      * @param color1   The color to use at the end of the sweep
      */
     public SweepGradient(float cx, float cy, int color0, int color1) {
+        mType = TYPE_COLOR_START_AND_COLOR_END;
+        mCx = cx;
+        mCy = cy;
+        mColor0 = color0;
+        mColor1 = color1;
         native_instance = nativeCreate2(cx, cy, color0, color1);
         native_shader = nativePostCreate2(native_instance, cx, cy, color0, color1);
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected Shader copy() {
+        final SweepGradient copy;
+        switch (mType) {
+            case TYPE_COLORS_AND_POSITIONS:
+                copy = new SweepGradient(mCx, mCy, mColors.clone(), mPositions.clone());
+                break;
+            case TYPE_COLOR_START_AND_COLOR_END:
+                copy = new SweepGradient(mCx, mCy, mColor0, mColor1);
+                break;
+            default:
+                throw new IllegalArgumentException("SweepGradient should be created with either " +
+                        "colors and positions or start color and end color");
+        }
+        copyLocalMatrix(copy);
+        return copy;
+    }
+
     private static native int nativeCreate1(float x, float y, int colors[], float positions[]);
     private static native int nativeCreate2(float x, float y, int color0, int color1);
 
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 8689261..5ceab36 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -23,12 +23,14 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.LayoutDirection;
 import android.view.Gravity;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -72,7 +74,10 @@
      // These are scaled to match the target density.
     private int mBitmapWidth;
     private int mBitmapHeight;
-    
+
+    // Mirroring matrix for using with Shaders
+    private Matrix mMirrorMatrix;
+
     /**
      * Create an empty drawable, not dealing with density.
      * @deprecated Use {@link #BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap)}
@@ -399,14 +404,51 @@
     }
 
     @Override
+    public void setAutoMirrored(boolean mirrored) {
+        if (mBitmapState.mAutoMirrored != mirrored) {
+            mBitmapState.mAutoMirrored = mirrored;
+            invalidateSelf();
+        }
+    }
+
+    @Override
+    public final boolean isAutoMirrored() {
+        return mBitmapState.mAutoMirrored;
+    }
+
+    @Override
     public int getChangingConfigurations() {
         return super.getChangingConfigurations() | mBitmapState.mChangingConfigurations;
     }
-    
+
+    private boolean needMirroring() {
+        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
+    }
+
+    private void updateMirrorMatrix(float dx) {
+        if (mMirrorMatrix == null) {
+            mMirrorMatrix = new Matrix();
+        }
+        mMirrorMatrix.setTranslate(dx, 0);
+        mMirrorMatrix.preScale(-1.0f, 1.0f);
+    }
+
     @Override
     protected void onBoundsChange(Rect bounds) {
         super.onBoundsChange(bounds);
         mApplyGravity = true;
+        Shader shader = mBitmapState.mPaint.getShader();
+        if (shader != null) {
+            if (needMirroring()) {
+                updateMirrorMatrix(bounds.right - bounds.left);
+                shader.setLocalMatrix(mMirrorMatrix);
+            } else {
+                if (mMirrorMatrix != null) {
+                    mMirrorMatrix = null;
+                    shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
+                }
+            }
+        }
     }
 
     @Override
@@ -430,6 +472,7 @@
             }
 
             Shader shader = state.mPaint.getShader();
+            final boolean needMirroring = needMirroring();
             if (shader == null) {
                 if (mApplyGravity) {
                     final int layoutDirection = getLayoutDirection();
@@ -437,12 +480,31 @@
                             getBounds(), mDstRect, layoutDirection);
                     mApplyGravity = false;
                 }
+                if (needMirroring) {
+                    canvas.save();
+                    // Mirror the bitmap
+                    canvas.translate(mDstRect.right - mDstRect.left, 0);
+                    canvas.scale(-1.0f, 1.0f);
+                }
                 canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint);
+                if (needMirroring) {
+                    canvas.restore();
+                }
             } else {
                 if (mApplyGravity) {
                     copyBounds(mDstRect);
                     mApplyGravity = false;
                 }
+                if (needMirroring) {
+                    // Mirror the bitmap
+                    updateMirrorMatrix(mDstRect.right - mDstRect.left);
+                    shader.setLocalMatrix(mMirrorMatrix);
+                } else {
+                    if (mMirrorMatrix != null) {
+                        mMirrorMatrix = null;
+                        shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
+                    }
+                }
                 canvas.drawRect(mDstRect, state.mPaint);
             }
         }
@@ -505,6 +567,8 @@
         setTargetDensity(r.getDisplayMetrics());
         setMipMap(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_mipMap,
                 bitmap.hasMipMap()));
+        setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_autoMirrored,
+                false));
 
         final Paint paint = mBitmapState.mPaint;
         paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias,
@@ -567,6 +631,7 @@
         Shader.TileMode mTileModeY = null;
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
         boolean mRebuildShader;
+        boolean mAutoMirrored;
 
         BitmapState(Bitmap bitmap) {
             mBitmap = bitmap;
@@ -581,6 +646,7 @@
             mTargetDensity = bitmapState.mTargetDensity;
             mPaint = new Paint(bitmapState.mPaint);
             mRebuildShader = bitmapState.mRebuildShader;
+            mAutoMirrored = bitmapState.mAutoMirrored;
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index c8fce9e..8135716 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -572,6 +572,25 @@
     }
 
     /**
+     * Set whether this Drawable is automatically mirrored when its layout direction is RTL
+     * (right-to left). See {@link android.util.LayoutDirection}.
+     *
+     * @param mirrored Set to true if the Drawable should be mirrored, false if not.
+     */
+    public void setAutoMirrored(boolean mirrored) {
+    }
+
+    /**
+     * Tells if this Drawable will be automatically mirrored  when its layout direction is RTL
+     * right-to-left. See {@link android.util.LayoutDirection}.
+     *
+     * @return boolean Returns true if this Drawable will be automatically mirrored.
+     */
+    public boolean isAutoMirrored() {
+        return false;
+    }
+
+    /**
      * Return the opacity/transparency of this Drawable.  The returned value is
      * one of the abstract format constants in
      * {@link android.graphics.PixelFormat}:
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index f9cd4e2..e350e8d 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -173,6 +173,19 @@
     }
 
     @Override
+    public void setAutoMirrored(boolean mirrored) {
+        mDrawableContainerState.mAutoMirrored = mirrored;
+        if (mCurrDrawable != null) {
+            mCurrDrawable.mutate().setAutoMirrored(mDrawableContainerState.mAutoMirrored);
+        }
+    }
+
+    @Override
+    public boolean isAutoMirrored() {
+        return mDrawableContainerState.mAutoMirrored;
+    }
+
+    @Override
     public void jumpToCurrentState() {
         boolean changed = false;
         if (mLastDrawable != null) {
@@ -334,6 +347,7 @@
                 d.setLevel(getLevel());
                 d.setBounds(getBounds());
                 d.setLayoutDirection(getLayoutDirection());
+                d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
             }
         } else {
             mCurrDrawable = null;
@@ -471,6 +485,8 @@
         int mEnterFadeDuration;
         int mExitFadeDuration;
 
+        boolean mAutoMirrored;
+
         DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
@@ -490,6 +506,7 @@
                 mLayoutDirection = orig.mLayoutDirection;
                 mEnterFadeDuration = orig.mEnterFadeDuration;
                 mExitFadeDuration = orig.mExitFadeDuration;
+                mAutoMirrored = orig.mAutoMirrored;
 
                 // Cloning the following values may require creating futures.
                 mConstantPadding = orig.getConstantPadding();
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 206897b..81cc11b 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -119,6 +119,9 @@
         mOpacityOverride = a.getInt(com.android.internal.R.styleable.LayerDrawable_opacity,
                 PixelFormat.UNKNOWN);
 
+        setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.LayerDrawable_autoMirrored,
+                false));
+
         a.recycle();
 
         final int innerDepth = parser.getDepth() + 1;
@@ -200,6 +203,7 @@
         st.mChildren[i] = childDrawable;
         childDrawable.mId = id;
         childDrawable.mDrawable = layer;
+        childDrawable.mDrawable.setAutoMirrored(isAutoMirrored());
         childDrawable.mInsetL = left;
         childDrawable.mInsetT = top;
         childDrawable.mInsetR = right;
@@ -448,6 +452,21 @@
     }
 
     @Override
+    public void setAutoMirrored(boolean mirrored) {
+        mLayerState.mAutoMirrored = mirrored;
+        final ChildDrawable[] array = mLayerState.mChildren;
+        final int N = mLayerState.mNum;
+        for (int i=0; i<N; i++) {
+            array[i].mDrawable.setAutoMirrored(mirrored);
+        }
+    }
+
+    @Override
+    public boolean isAutoMirrored() {
+        return mLayerState.mAutoMirrored;
+    }
+
+    @Override
     public boolean isStateful() {
         return mLayerState.isStateful();
     }
@@ -630,6 +649,8 @@
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
+        private boolean mAutoMirrored;
+
         LayerState(LayerState orig, LayerDrawable owner, Resources res) {
             if (orig != null) {
                 final ChildDrawable[] origChildDrawable = orig.mChildren;
@@ -663,6 +684,7 @@
                 mHaveStateful = orig.mHaveStateful;
                 mStateful = orig.mStateful;
                 mCheckedConstantState = mCanConstantState = true;
+                mAutoMirrored = orig.mAutoMirrored;
             } else {
                 mNum = 0;
                 mChildren = null;
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 86e4bad..720494b 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -30,6 +30,7 @@
 import android.graphics.Region;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.LayoutDirection;
 import android.util.TypedValue;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -132,6 +133,7 @@
             // lazy allocation of a paint
             setDither(state.mDither);
         }
+        setAutoMirrored(state.mAutoMirrored);
         if (mNinePatch != null) {
             computeBitmapSize();
         }
@@ -216,7 +218,19 @@
 
     @Override
     public void draw(Canvas canvas) {
-        mNinePatch.draw(canvas, getBounds(), mPaint);
+        final Rect bounds = getBounds();
+        final boolean needMirroring = isAutoMirrored() &&
+                getLayoutDirection() == LayoutDirection.RTL;
+        if (needMirroring) {
+            canvas.save();
+            // Mirror the 9patch
+            canvas.translate(bounds.right - bounds.left, 0);
+            canvas.scale(-1.0f, 1.0f);
+        }
+        mNinePatch.draw(canvas, bounds, mPaint);
+        if (needMirroring) {
+            canvas.restore();
+        }
     }
 
     @Override
@@ -279,6 +293,16 @@
     }
 
     @Override
+    public void setAutoMirrored(boolean mirrored) {
+        mNinePatchState.mAutoMirrored = mirrored;
+    }
+
+    @Override
+    public boolean isAutoMirrored() {
+        return mNinePatchState.mAutoMirrored;
+    }
+
+    @Override
     public void setFilterBitmap(boolean filter) {
         getPaint().setFilterBitmap(filter);
         invalidateSelf();
@@ -328,8 +352,11 @@
                     ": <nine-patch> requires a valid 9-patch source image");
         }
 
+        final boolean automirrored = a.getBoolean(
+                com.android.internal.R.styleable.NinePatchDrawable_autoMirrored, false);
+
         setNinePatchState(new NinePatchState(new NinePatch(bitmap, bitmap.getNinePatchChunk()),
-                padding, opticalInsets, dither), r);
+                padding, opticalInsets, dither, automirrored), r);
         mNinePatchState.mTargetDensity = mTargetDensity;
 
         a.recycle();
@@ -407,20 +434,23 @@
         final boolean mDither;
         int mChangingConfigurations;
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+        boolean mAutoMirrored;
 
         NinePatchState(NinePatch ninePatch, Rect padding) {
-            this(ninePatch, padding, new Rect(), DEFAULT_DITHER);
+            this(ninePatch, padding, new Rect(), DEFAULT_DITHER, false);
         }
 
         NinePatchState(NinePatch ninePatch, Rect padding, Rect opticalInsets) {
-            this(ninePatch, padding, opticalInsets, DEFAULT_DITHER);
+            this(ninePatch, padding, opticalInsets, DEFAULT_DITHER, false);
         }
 
-        NinePatchState(NinePatch ninePatch, Rect rect, Rect opticalInsets, boolean dither) {
+        NinePatchState(NinePatch ninePatch, Rect rect, Rect opticalInsets, boolean dither,
+                       boolean autoMirror) {
             mNinePatch = ninePatch;
             mPadding = rect;
             mOpticalInsets = Insets.of(opticalInsets);
             mDither = dither;
+            mAutoMirrored = autoMirror;
         }
 
         // Copy constructor
@@ -434,6 +464,7 @@
             mDither = state.mDither;
             mChangingConfigurations = state.mChangingConfigurations;
             mTargetDensity = state.mTargetDensity;
+            mAutoMirrored = state.mAutoMirrored;
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index e3c7bc5..48d66b7 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -132,6 +132,9 @@
         setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither,
                                DEFAULT_DITHER));
 
+        setAutoMirrored(a.getBoolean(
+                com.android.internal.R.styleable.StateListDrawable_autoMirrored, false));
+
         a.recycle();
 
         int type;
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 6ac637e..df966e1 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -256,8 +256,12 @@
     log.appendFormat("  PatchCache           %8d / %8d\n",
             patchCache.getSize(), patchCache.getMaxSize());
     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
-        const uint32_t size = fontRenderer->getFontRendererSize(i);
-        log.appendFormat("  FontRenderer %d       %8d / %8d\n", i, size, size);
+        const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA);
+        const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA);
+        log.appendFormat("  FontRenderer %d A8    %8d / %8d\n", i, sizeA8, sizeA8);
+        log.appendFormat("  FontRenderer %d RGBA  %8d / %8d\n", i, sizeRGBA, sizeRGBA);
+        log.appendFormat("  FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA,
+                sizeA8 + sizeRGBA);
     }
     log.appendFormat("Other:\n");
     log.appendFormat("  FboCache             %8d / %8d\n",
@@ -272,7 +276,8 @@
     total += dropShadowCache.getSize();
     total += patchCache.getSize();
     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
-        total += fontRenderer->getFontRendererSize(i);
+        total += fontRenderer->getFontRendererSize(i, GL_ALPHA);
+        total += fontRenderer->getFontRendererSize(i, GL_RGBA);
     }
 
     log.appendFormat("Total memory usage:\n");
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 5ac2511..be0800f 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -594,7 +594,6 @@
 
 private:
     SkRegion* mRegion;
-    SkRegion::Op mOp;
 };
 
 class ResetShaderOp : public StateOp {
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 79a7a93..1b2f651 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -21,7 +21,6 @@
 
 #include <cutils/properties.h>
 
-#include <utils/Functor.h>
 #include <utils/Log.h>
 
 #ifdef ANDROID_ENABLE_RENDERSCRIPT
@@ -35,6 +34,7 @@
 #include "Debug.h"
 #include "Extensions.h"
 #include "FontRenderer.h"
+#include "OpenGLRenderer.h"
 #include "PixelBuffer.h"
 #include "Rect.h"
 
@@ -45,6 +45,52 @@
 #define RS_MIN_INPUT_CUTOFF 10000
 
 ///////////////////////////////////////////////////////////////////////////////
+// TextSetupFunctor
+///////////////////////////////////////////////////////////////////////////////
+status_t TextSetupFunctor::operator ()(int what, void* data) {
+    Data* typedData = reinterpret_cast<Data*>(data);
+    GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;
+
+    renderer->setupDraw();
+    renderer->setupDrawTextGamma(paint);
+    renderer->setupDrawDirtyRegionsDisabled();
+    renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA);
+    switch (glyphFormat) {
+        case GL_ALPHA: {
+            renderer->setupDrawAlpha8Color(paint->getColor(), alpha);
+            break;
+        }
+        case GL_RGBA: {
+            float floatAlpha = alpha / 255.0f;
+            renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
+            break;
+        }
+        default: {
+#if DEBUG_FONT_RENDERER
+            ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat);
+#endif
+            break;
+        }
+    }
+    renderer->setupDrawColorFilter();
+    renderer->setupDrawShader();
+    renderer->setupDrawBlending(true, mode);
+    renderer->setupDrawProgram();
+    renderer->setupDrawModelView(x, y, x, y, pureTranslate, true);
+    // Calling setupDrawTexture with the name 0 will enable the
+    // uv attributes and increase the texture unit count
+    // texture binding will be performed by the font renderer as
+    // needed
+    renderer->setupDrawTexture(0);
+    renderer->setupDrawPureColorUniforms();
+    renderer->setupDrawColorFilterUniforms();
+    renderer->setupDrawShaderUniforms(pureTranslate);
+    renderer->setupDrawTextGammaUniforms();
+
+    return NO_ERROR;
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // FontRenderer
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -103,11 +149,16 @@
     sLogFontRendererCreate = false;
 }
 
-FontRenderer::~FontRenderer() {
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        delete mCacheTextures[i];
+void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        delete cacheTextures[i];
     }
-    mCacheTextures.clear();
+    cacheTextures.clear();
+}
+
+FontRenderer::~FontRenderer() {
+    clearCacheTextures(mACacheTextures);
+    clearCacheTextures(mRGBACacheTextures);
 
     LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
     while (it.next()) {
@@ -124,15 +175,19 @@
         it.value()->invalidateTextureCache();
     }
 
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        mCacheTextures[i]->init();
+    for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
+        mACacheTextures[i]->init();
+    }
+
+    for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
+        mRGBACacheTextures[i]->init();
     }
 }
 
-void FontRenderer::flushLargeCaches() {
+void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
     // Start from 1; don't deallocate smallest/default texture
-    for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
-        CacheTexture* cacheTexture = mCacheTextures[i];
+    for (uint32_t i = 1; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
         if (cacheTexture->getPixelBuffer()) {
             cacheTexture->init();
             LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
@@ -144,11 +199,16 @@
     }
 }
 
-CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph,
-        uint32_t* startX, uint32_t* startY) {
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        if (mCacheTextures[i]->fitBitmap(glyph, startX, startY)) {
-            return mCacheTextures[i];
+void FontRenderer::flushLargeCaches() {
+    flushLargeCaches(mACacheTextures);
+    flushLargeCaches(mRGBACacheTextures);
+}
+
+CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
+        const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
+            return cacheTextures[i];
         }
     }
     // Could not fit glyph into current cache textures
@@ -169,9 +229,26 @@
 
     cachedGlyph->mIsValid = false;
 
+    // choose an appropriate cache texture list for this glyph format
+    SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
+    Vector<CacheTexture*>* cacheTextures = NULL;
+    switch (format) {
+        case SkMask::kA8_Format:
+            cacheTextures = &mACacheTextures;
+            break;
+        case SkMask::kARGB32_Format:
+            cacheTextures = &mRGBACacheTextures;
+            break;
+        default:
+#if DEBUG_FONT_RENDERER
+            ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
+#endif
+        return;
+    }
+
     // If the glyph is too tall, don't cache it
     if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
-                mCacheTextures[mCacheTextures.size() - 1]->getHeight()) {
+                (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
         ALOGE("Font size too large to fit in cache. width, height = %i, %i",
                 (int) glyph.fWidth, (int) glyph.fHeight);
         return;
@@ -181,14 +258,14 @@
     uint32_t startX = 0;
     uint32_t startY = 0;
 
-    CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
+    CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
 
     if (!cacheTexture) {
         if (!precaching) {
             // If the new glyph didn't fit and we are not just trying to precache it,
             // clear out the cache and try again
             flushAllAndInvalidate();
-            cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
+            cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
         }
 
         if (!cacheTexture) {
@@ -216,24 +293,21 @@
         cacheTexture->allocateMesh();
     }
 
-    // Tells us whether the glyphs is B&W (1 bit per pixel)
-    // or anti-aliased (8 bits per pixel)
-    SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
-
     uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
-    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
+    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
+    int srcStride = glyph.rowBytes();
 
     // Copy the glyph image, taking the mask format into account
-    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
-    int stride = glyph.rowBytes();
-
-    uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
-    memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
-
     switch (format) {
         case SkMask::kA8_Format: {
+            uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
+            uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
+                    - TEXTURE_BORDER_SIZE;
+            // write leading border line
+            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
+            // write glyph data
             if (mGammaTable) {
-                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) {
+                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
                     row = cacheY * cacheWidth;
                     cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
                     for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
@@ -243,21 +317,55 @@
                     cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
                 }
             } else {
-                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) {
+                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
                     row = cacheY * cacheWidth;
                     memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
                     cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
                     cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
                 }
             }
+            // write trailing border line
+            row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
+            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
+            break;
+        }
+        case SkMask::kARGB32_Format: {
+            // prep data lengths
+            const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
+            const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
+            size_t rowSize = formatSize * glyph.fWidth;
+            // prep advances
+            size_t dstStride = formatSize * cacheWidth;
+            // prep indices
+            // - we actually start one row early, and then increment before first copy
+            uint8_t* src = &bitmapBuffer[0 - srcStride];
+            uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
+            uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
+            uint8_t* dstL = dst - borderSize;
+            uint8_t* dstR = dst + rowSize;
+            // write leading border line
+            memset(dstL, 0, rowSize + 2 * borderSize);
+            // write glyph data
+            while (dst < dstEnd) {
+                memset(dstL += dstStride, 0, borderSize); // leading border column
+                memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
+                memset(dstR += dstStride, 0, borderSize); // trailing border column
+            }
+            // write trailing border line
+            memset(dstL, 0, rowSize + 2 * borderSize);
             break;
         }
         case SkMask::kBW_Format: {
+            uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
+            uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
+                    - TEXTURE_BORDER_SIZE;
             static const uint8_t COLORS[2] = { 0, 255 };
-
+            // write leading border line
+            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
+            // write glyph data
             for (cacheY = startY; cacheY < endY; cacheY++) {
                 cacheX = startX;
-                int rowBytes = stride;
+                int rowBytes = srcStride;
                 uint8_t* buffer = bitmapBuffer;
 
                 row = cacheY * cacheWidth;
@@ -270,23 +378,24 @@
                 }
                 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
 
-                bitmapBuffer += stride;
+                bitmapBuffer += srcStride;
             }
+            // write trailing border line
+            row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
+            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
             break;
         }
         default:
-            ALOGW("Unkown glyph format: 0x%x", format);
+            ALOGW("Unknown glyph format: 0x%x", format);
             break;
     }
 
-    row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
-    memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
-
     cachedGlyph->mIsValid = true;
 }
 
-CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
-    CacheTexture* cacheTexture = new CacheTexture(width, height, gMaxNumberOfQuads);
+CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
+        bool allocate) {
+    CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
 
     if (allocate) {
         Caches::getInstance().activeTexture(0);
@@ -298,17 +407,23 @@
 }
 
 void FontRenderer::initTextTexture() {
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        delete mCacheTextures[i];
-    }
-    mCacheTextures.clear();
+    clearCacheTextures(mACacheTextures);
+    clearCacheTextures(mRGBACacheTextures);
 
     mUploadTexture = false;
-    mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true));
-    mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false));
-    mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false));
-    mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, false));
-    mCurrentCacheTexture = mCacheTextures[0];
+    mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
+            GL_ALPHA, true));
+    mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
+            GL_ALPHA, false));
+    mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
+            GL_ALPHA, false));
+    mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
+            GL_ALPHA, false));
+    mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
+            GL_RGBA, false));
+    mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
+            GL_RGBA, false));
+    mCurrentCacheTexture = mACacheTextures[0];
 }
 
 // We don't want to allocate anything unless we actually draw text
@@ -322,6 +437,24 @@
     mInitialized = true;
 }
 
+void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
+        bool& resetPixelStore, GLuint& lastTextureId) {
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
+        if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
+            if (cacheTexture->getTextureId() != lastTextureId) {
+                lastTextureId = cacheTexture->getTextureId();
+                caches.activeTexture(0);
+                caches.bindTexture(lastTextureId);
+            }
+
+            if (cacheTexture->upload()) {
+                resetPixelStore = true;
+            }
+        }
+    }
+}
+
 void FontRenderer::checkTextureUpdate() {
     if (!mUploadTexture) {
         return;
@@ -334,25 +467,8 @@
     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->getPixelBuffer()) {
-            if (cacheTexture->getTextureId() != lastTextureId) {
-                lastTextureId = cacheTexture->getTextureId();
-                caches.activeTexture(0);
-                caches.bindTexture(lastTextureId);
-            }
-
-            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
-        }
-    }
+    checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
+    checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
 
     // Unbind any PBO we might have used to update textures
     caches.unbindPixelBuffer();
@@ -366,18 +482,18 @@
     mUploadTexture = false;
 }
 
-void FontRenderer::issueDrawCommand() {
+void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
+    Caches& caches = Caches::getInstance();
     bool first = true;
     bool force = false;
-
-    GLuint lastId = 0;
-    Caches& caches = Caches::getInstance();
-
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        CacheTexture* texture = mCacheTextures[i];
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* texture = cacheTextures[i];
         if (texture->canDraw()) {
             if (first) {
-                if (mFunctor) (*mFunctor)(0, NULL);
+                if (mFunctor) {
+                    TextSetupFunctor::Data functorData(texture->getFormat());
+                    (*mFunctor)(0, &functorData);
+                }
 
                 checkTextureUpdate();
                 caches.bindIndicesBuffer();
@@ -407,6 +523,11 @@
             texture->resetMesh();
         }
     }
+}
+
+void FontRenderer::issueDrawCommand() {
+    issueDrawCommand(mACacheTextures);
+    issueDrawCommand(mRGBACacheTextures);
 
     mDrawn = true;
 }
@@ -582,13 +703,13 @@
 
 bool FontRenderer::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) {
+        float hOffset, float vOffset, Rect* bounds, Functor* functor) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
     }
 
-    initRender(clip, bounds, NULL);
+    initRender(clip, bounds, functor);
     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
     finishRender();
 
@@ -646,10 +767,10 @@
     delete[] scratch;
 }
 
-uint32_t FontRenderer::getCacheSize() const {
+static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
     uint32_t size = 0;
-    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
-        CacheTexture* cacheTexture = mCacheTextures[i];
+    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = cacheTextures[i];
         if (cacheTexture && cacheTexture->getPixelBuffer()) {
             size += cacheTexture->getPixelBuffer()->getSize();
         }
@@ -657,5 +778,19 @@
     return size;
 }
 
+uint32_t FontRenderer::getCacheSize(GLenum format) const {
+    switch (format) {
+        case GL_ALPHA: {
+            return calculateCacheSize(mACacheTextures);
+        }
+        case GL_RGBA: {
+            return calculateCacheSize(mRGBACacheTextures);
+        }
+        default: {
+            return 0;
+        }
+    }
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index c1072ed..aca47b4 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HWUI_FONT_RENDERER_H
 #define ANDROID_HWUI_FONT_RENDERER_H
 
+#include <utils/Functor.h>
 #include <utils/LruCache.h>
 #include <utils/Vector.h>
 #include <utils/StrongPointer.h>
@@ -46,8 +47,40 @@
 namespace android {
 namespace uirenderer {
 
+class OpenGLRenderer;
+
 ///////////////////////////////////////////////////////////////////////////////
-// Renderer
+// TextSetupFunctor
+///////////////////////////////////////////////////////////////////////////////
+class TextSetupFunctor: public Functor {
+public:
+    struct Data {
+        Data(GLenum glyphFormat) : glyphFormat(glyphFormat) {
+        }
+
+        GLenum glyphFormat;
+    };
+
+    TextSetupFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate,
+            int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(),
+            renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
+            alpha(alpha), mode(mode), paint(paint) {
+    }
+    ~TextSetupFunctor() { }
+
+    status_t operator ()(int what, void* data);
+
+    OpenGLRenderer* renderer;
+    float x;
+    float y;
+    bool pureTranslate;
+    int alpha;
+    SkXfermode::Mode mode;
+    SkPaint* paint;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// FontRenderer
 ///////////////////////////////////////////////////////////////////////////////
 
 class FontRenderer {
@@ -55,6 +88,7 @@
     FontRenderer();
     ~FontRenderer();
 
+    void flushLargeCaches(Vector<CacheTexture*>& cacheTextures);
     void flushLargeCaches();
 
     void setGammaTable(const uint8_t* gammaTable) {
@@ -73,7 +107,8 @@
 
     // 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);
+            uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds,
+            Functor* functor);
 
     struct DropShadow {
         DropShadow() { };
@@ -100,7 +135,7 @@
         mLinearFiltering = linearFiltering;
     }
 
-    uint32_t getCacheSize() const;
+    uint32_t getCacheSize(GLenum format) const;
 
 private:
     friend class Font;
@@ -110,10 +145,11 @@
     void allocateTextureMemory(CacheTexture* cacheTexture);
     void deallocateTextureMemory(CacheTexture* cacheTexture);
     void initTextTexture();
-    CacheTexture* createCacheTexture(int width, int height, bool allocate);
+    CacheTexture* createCacheTexture(int width, int height, GLenum format, bool allocate);
     void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
             uint32_t *retOriginX, uint32_t *retOriginY, bool precaching);
-    CacheTexture* cacheBitmapInTexture(const SkGlyph& glyph, uint32_t* startX, uint32_t* startY);
+    CacheTexture* cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures, const SkGlyph& glyph,
+            uint32_t* startX, uint32_t* startY);
 
     void flushAllAndInvalidate();
 
@@ -121,6 +157,7 @@
     void initRender(const Rect* clip, Rect* bounds, Functor* functor);
     void finishRender();
 
+    void issueDrawCommand(Vector<CacheTexture*>& cacheTextures);
     void issueDrawCommand();
     void appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
             float x2, float y2, float u2, float v2,
@@ -148,7 +185,8 @@
     uint32_t mLargeCacheWidth;
     uint32_t mLargeCacheHeight;
 
-    Vector<CacheTexture*> mCacheTextures;
+    Vector<CacheTexture*> mACacheTextures;
+    Vector<CacheTexture*> mRGBACacheTextures;
 
     Font* mCurrentFont;
     LruCache<Font::FontDescription, Font*> mActiveFonts;
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index bbfa66d..46cfd04 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -35,7 +35,7 @@
     virtual FontRenderer& getFontRenderer(const SkPaint* paint) = 0;
 
     virtual uint32_t getFontRendererCount() const = 0;
-    virtual uint32_t getFontRendererSize(uint32_t fontRenderer) const = 0;
+    virtual uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const = 0;
 
     virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0;
     virtual void setupProgram(ProgramDescription& description, Program* program) const = 0;
@@ -81,8 +81,8 @@
         return 1;
     }
 
-    uint32_t getFontRendererSize(uint32_t fontRenderer) const {
-        return mRenderer ? mRenderer->getCacheSize() : 0;
+    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+        return mRenderer ? mRenderer->getCacheSize(format) : 0;
     }
 
     void describe(ProgramDescription& description, const SkPaint* paint) const;
@@ -128,8 +128,8 @@
         return 1;
     }
 
-    uint32_t getFontRendererSize(uint32_t fontRenderer) const {
-        return mRenderer ? mRenderer->getCacheSize() : 0;
+    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+        return mRenderer ? mRenderer->getCacheSize(format) : 0;
     }
 
     void describe(ProgramDescription& description, const SkPaint* paint) const {
@@ -162,13 +162,13 @@
         return kGammaCount;
     }
 
-    uint32_t getFontRendererSize(uint32_t fontRenderer) const {
+    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
         if (fontRenderer >= kGammaCount) return 0;
 
         FontRenderer* renderer = mRenderers[fontRenderer];
         if (!renderer) return 0;
 
-        return renderer->getCacheSize();
+        return renderer->getCacheSize(format);
     }
 
     void describe(ProgramDescription& description, const SkPaint* paint) const {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index bc00ce8..36be9a7 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1668,7 +1668,7 @@
     SkPath path;
     path.addRect(left, top, right, bottom);
 
-    return clipPath(&path, op);
+    return OpenGLRenderer::clipPath(&path, op);
 }
 
 bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) {
@@ -1679,11 +1679,15 @@
     path->transform(transform, &transformed);
 
     SkRegion clip;
-    if (!mSnapshot->clipRegion->isEmpty()) {
-        clip.setRegion(*mSnapshot->clipRegion);
+    if (!mSnapshot->previous->clipRegion->isEmpty()) {
+        clip.setRegion(*mSnapshot->previous->clipRegion);
     } else {
-        Rect* bounds = mSnapshot->clipRect;
-        clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
+        if (mSnapshot->previous == mFirstSnapshot) {
+            clip.setRect(0, 0, mWidth, mHeight);
+        } else {
+            Rect* bounds = mSnapshot->previous->clipRect;
+            clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
+        }
     }
 
     SkRegion region;
@@ -2825,48 +2829,6 @@
     return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
 }
 
-class TextSetupFunctor: public Functor {
-public:
-    TextSetupFunctor(OpenGLRenderer& renderer, float x, float y, bool pureTranslate,
-            int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(),
-            renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
-            alpha(alpha), mode(mode), paint(paint) {
-    }
-    ~TextSetupFunctor() { }
-
-    status_t operator ()(int what, void* data) {
-        renderer.setupDraw();
-        renderer.setupDrawTextGamma(paint);
-        renderer.setupDrawDirtyRegionsDisabled();
-        renderer.setupDrawWithTexture(true);
-        renderer.setupDrawAlpha8Color(paint->getColor(), alpha);
-        renderer.setupDrawColorFilter();
-        renderer.setupDrawShader();
-        renderer.setupDrawBlending(true, mode);
-        renderer.setupDrawProgram();
-        renderer.setupDrawModelView(x, y, x, y, pureTranslate, true);
-        // Calling setupDrawTexture with the name 0 will enable the
-        // uv attributes and increase the texture unit count
-        // texture binding will be performed by the font renderer as
-        // needed
-        renderer.setupDrawTexture(0);
-        renderer.setupDrawPureColorUniforms();
-        renderer.setupDrawColorFilterUniforms();
-        renderer.setupDrawShaderUniforms(pureTranslate);
-        renderer.setupDrawTextGammaUniforms();
-
-        return NO_ERROR;
-    }
-
-    OpenGLRenderer& renderer;
-    float x;
-    float y;
-    bool pureTranslate;
-    int alpha;
-    SkXfermode::Mode mode;
-    SkPaint* paint;
-};
-
 status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, SkPaint* paint) {
     if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
@@ -2912,7 +2874,7 @@
 
     const bool hasActiveLayer = hasLayer();
 
-    TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
+    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
             positions, hasActiveLayer ? &bounds : NULL, &functor)) {
         if (hasActiveLayer) {
@@ -3003,7 +2965,7 @@
     Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     bool status;
-    TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
+    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
 
     // don't call issuedrawcommand, do it at end of batch
     bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
@@ -3045,26 +3007,7 @@
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
-
-    setupDraw();
-    setupDrawTextGamma(paint);
-    setupDrawDirtyRegionsDisabled();
-    setupDrawWithTexture(true);
-    setupDrawAlpha8Color(paint->getColor(), alpha);
-    setupDrawColorFilter();
-    setupDrawShader();
-    setupDrawBlending(true, mode);
-    setupDrawProgram();
-    setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true);
-    // Calling setupDrawTexture with the name 0 will enable the
-    // uv attributes and increase the texture unit count
-    // texture binding will be performed by the font renderer as
-    // needed
-    setupDrawTexture(0);
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
-    setupDrawShaderUniforms(false);
-    setupDrawTextGammaUniforms();
+    TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
 
     const Rect* clip = &mSnapshot->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
@@ -3072,7 +3015,7 @@
     const bool hasActiveLayer = hasLayer();
 
     if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
-            hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) {
+            hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) {
         if (hasActiveLayer) {
             currentTransform().mapRect(bounds);
             dirtyLayerUnchecked(bounds, getRegion());
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 32d5417..9725a61 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -112,13 +112,25 @@
     virtual uint8_t* getMappedPointer() const = 0;
 
     /**
-     * Upload the specified rectangle of this pixe buffer as a
+     * Upload the specified rectangle of this pixel 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;
 
     /**
+     * Upload the specified rectangle of this pixel buffer as a
+     * GL_TEXTURE_2D texture. Calling this method will trigger
+     * an unmap() if necessary.
+     *
+     * This is a convenience function provided to save callers the
+     * trouble of computing the offset parameter.
+     */
+    void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
+        upload(x, y, width, height, getOffset(x, y));
+    }
+
+    /**
      * Returns the width of the render buffer in pixels.
      */
     uint32_t getWidth() const {
@@ -140,6 +152,13 @@
     }
 
     /**
+     * Returns the offset of a pixel in this pixel buffer, in bytes.
+     */
+    uint32_t getOffset(uint32_t x, uint32_t y) const {
+        return (y * mWidth + x) * formatSize(mFormat);
+    }
+
+    /**
      * Returns the number of bytes per pixel in the specified format.
      *
      * Supported formats:
diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/Stencil.cpp
index ba2e6f2..2764523 100644
--- a/libs/hwui/Stencil.cpp
+++ b/libs/hwui/Stencil.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "Debug.h"
 #include "Extensions.h"
 #include "Properties.h"
 #include "Stencil.h"
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 5f15724..55503ce 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -108,8 +108,8 @@
 // CacheTexture
 ///////////////////////////////////////////////////////////////////////////////
 
-CacheTexture::CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount) :
-            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
+CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) :
+            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), mFormat(format),
             mLinearFiltering(false), mDirty(false), mNumGlyphs(0),
             mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount),
             mCaches(Caches::getInstance()) {
@@ -182,7 +182,7 @@
 
 void CacheTexture::allocateTexture() {
     if (!mTexture) {
-        mTexture = PixelBuffer::create(GL_ALPHA, mWidth, mHeight);
+        mTexture = PixelBuffer::create(mFormat, mWidth, mHeight);
     }
 
     if (!mTextureId) {
@@ -191,8 +191,8 @@
         mCaches.bindTexture(mTextureId);
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         // Initialize texture dimensions
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0,
-                GL_ALPHA, GL_UNSIGNED_BYTE, 0);
+        glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
+                mFormat, GL_UNSIGNED_BYTE, 0);
 
         const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
@@ -217,8 +217,7 @@
         glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth);
     }
 
-    mTexture->upload(x, y, width, height, y * mWidth + x);
-
+    mTexture->upload(x, y, width, height);
     setDirty(false);
 
     return mHasES3;
@@ -232,6 +231,30 @@
 }
 
 bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
+    switch (glyph.fMaskFormat) {
+        case SkMask::kA8_Format:
+            if (mFormat != GL_ALPHA) {
+#if DEBUG_FONT_RENDERER
+                ALOGD("fitBitmap: kA8_Format glyph cannot fit into texture format %x", mFormat);
+#endif
+                return false;
+            }
+            break;
+        case SkMask::kARGB32_Format:
+            if (mFormat != GL_RGBA) {
+#if DEBUG_FONT_RENDERER
+                ALOGD("fitBitmap: kARGB32_Format glyph cannot fit into texture format %x", mFormat);
+#endif
+                return false;
+            }
+            break;
+        default:
+#if DEBUG_FONT_RENDERER
+            ALOGD("fitBitmap: unknown glyph format %x encountered", glyph.fMaskFormat);
+#endif
+            return false;
+    }
+
     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 208b1ff..028b611 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -24,6 +24,7 @@
 #include <utils/Log.h>
 
 #include "FontUtil.h"
+#include "../PixelBuffer.h"
 #include "../Rect.h"
 #include "../Vertex.h"
 
@@ -31,7 +32,6 @@
 namespace uirenderer {
 
 class Caches;
-class PixelBuffer;
 
 /**
  * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
@@ -74,7 +74,7 @@
 
 class CacheTexture {
 public:
-    CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount);
+    CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount);
     ~CacheTexture();
 
     void reset();
@@ -100,6 +100,14 @@
         return mHeight;
     }
 
+    inline GLenum getFormat() const {
+        return mFormat;
+    }
+
+    inline uint32_t getOffset(uint16_t x, uint16_t y) const {
+        return (y * mWidth + x) * PixelBuffer::formatSize(mFormat);
+    }
+
     inline const Rect* getDirtyRect() const {
         return &mDirtyRect;
     }
@@ -173,6 +181,7 @@
     GLuint mTextureId;
     uint16_t mWidth;
     uint16_t mHeight;
+    GLenum mFormat;
     bool mLinearFiltering;
     bool mDirty;
     uint16_t mNumGlyphs;
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
index f758666..cdcb23c 100644
--- a/libs/hwui/font/FontUtil.h
+++ b/libs/hwui/font/FontUtil.h
@@ -31,6 +31,9 @@
 #define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512
 
 #define TEXTURE_BORDER_SIZE 1
+#if TEXTURE_BORDER_SIZE != 1
+# error TEXTURE_BORDER_SIZE other than 1 is not currently supported
+#endif
 
 #define CACHE_BLOCK_ROUNDING_SIZE 4
 
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 5ebba93..ee748d39 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -147,6 +147,7 @@
     private int mNumUpdates = Integer.MAX_VALUE;  // no expiry
     private float mSmallestDisplacement = 0.0f;    // meters
     private WorkSource mWorkSource = new WorkSource();
+    private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
 
     private String mProvider = LocationManager.FUSED_PROVIDER;  // for deprecated APIs that explicitly request a provider
 
@@ -236,6 +237,7 @@
         mSmallestDisplacement = src.mSmallestDisplacement;
         mProvider = src.mProvider;
         mWorkSource = src.mWorkSource;
+        mHideFromAppOps = src.mHideFromAppOps;
     }
 
     /**
@@ -506,6 +508,16 @@
         return mWorkSource;
     }
 
+    /** @hide */
+    public void setHideFromAppOps(boolean hideFromAppOps) {
+        mHideFromAppOps = hideFromAppOps;
+    }
+
+    /** @hide */
+    public boolean getHideFromAppOps() {
+        return mHideFromAppOps;
+    }
+
     private static void checkInterval(long millis) {
         if (millis < 0) {
             throw new IllegalArgumentException("invalid interval: " + millis);
@@ -549,6 +561,7 @@
             request.setExpireAt(in.readLong());
             request.setNumUpdates(in.readInt());
             request.setSmallestDisplacement(in.readFloat());
+            request.setHideFromAppOps(in.readInt() != 0);
             String provider = in.readString();
             if (provider != null) request.setProvider(provider);
             WorkSource workSource = in.readParcelable(WorkSource.class.getClassLoader());
@@ -574,6 +587,7 @@
         parcel.writeLong(mExpireAt);
         parcel.writeInt(mNumUpdates);
         parcel.writeFloat(mSmallestDisplacement);
+        parcel.writeInt(mHideFromAppOps ? 1 : 0);
         parcel.writeString(mProvider);
         parcel.writeParcelable(mWorkSource, 0);
     }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index bcd0398..14cdbb7 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1555,6 +1555,22 @@
 
     /**
      * @hide
+     * Checks whether the current audio focus is exclusive.
+     * @return true if the top of the audio focus stack requested focus
+     *     with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
+     */
+    public boolean isAudioFocusExclusive() {
+        IAudioService service = getService();
+        try {
+            return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in isAudioFocusExclusive()", e);
+            return false;
+        }
+    }
+
+    /**
+     * @hide
      * If the stream is active locally or remotely, adjust its volume according to the enforced
      * priority rules.
      * Note: only AudioManager.STREAM_MUSIC is supported at the moment
@@ -1771,6 +1787,12 @@
     }
 
     /**
+     * @hide
+     * Used to indicate no audio focus has been gained or lost.
+     */
+    public static final int AUDIOFOCUS_NONE = 0;
+
+    /**
      * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
@@ -1795,6 +1817,15 @@
      */
     public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
     /**
+     * Used to indicate a temporary request of audio focus, anticipated to last a short
+     * amount of time, during which no other applications, or system components, should play
+     * anything. Examples of exclusive and transient audio focus requests are voice
+     * memo recording and speech recognition, during which the system shouldn't play any
+     * notifications, and media playback should have paused.
+     * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
+     */
+    public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
+    /**
      * Used to indicate a loss of audio focus of unknown duration.
      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
      */
@@ -1958,14 +1989,17 @@
      *      for the playback of driving directions, or notifications sounds.
      *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
      *      the previous focus owner to keep playing if it ducks its audio output.
+     *      Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
+     *      that benefits from the system not playing disruptive sounds like notifications, for
+     *      usecases such as voice memo recording, or speech recognition.
      *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
      *      as the playback of a song or a video.
      *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
      */
     public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
         int status = AUDIOFOCUS_REQUEST_FAILED;
-        if ((durationHint < AUDIOFOCUS_GAIN) || (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK))
-        {
+        if ((durationHint < AUDIOFOCUS_GAIN) ||
+                (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
             Log.e(TAG, "Invalid duration hint, audio focus request denied");
             return status;
         }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index c178ae4..290866e 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -4198,6 +4198,10 @@
         mMediaFocusControl.unregisterAudioFocusClient(clientId);
     }
 
+    public int getCurrentAudioFocus() {
+        return mMediaFocusControl.getCurrentAudioFocus();
+    }
+
     //==========================================================================================
     // Device orientation
     //==========================================================================================
diff --git a/media/java/android/media/FocusRequester.java b/media/java/android/media/FocusRequester.java
index 020f3e1..9a39994 100644
--- a/media/java/android/media/FocusRequester.java
+++ b/media/java/android/media/FocusRequester.java
@@ -30,11 +30,6 @@
  */
 class FocusRequester {
 
-    /**
-     * Used to indicate no audio focus has been gained or lost.
-     */
-    private static final int AUDIOFOCUS_NONE = 0;
-
     // on purpose not using this classe's name, as it will only be used from MediaFocusControl
     private static final String TAG = "MediaFocusControl";
     private static final boolean DEBUG = false;
@@ -50,7 +45,7 @@
      */
     private final int mFocusGainRequest;
     /**
-     * the audio focus loss received my mFocusDispatcher, is MediaFocusControl.AUDIOFOCUS_NONE if
+     * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
      *  it never lost focus.
      */
     private int mFocusLossReceived;
@@ -70,7 +65,7 @@
         mPackageName = pn;
         mCallingUid = uid;
         mFocusGainRequest = focusRequest;
-        mFocusLossReceived = AUDIOFOCUS_NONE;
+        mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
     }
 
 
@@ -110,7 +105,7 @@
 
     private static String focusChangeToString(int focus) {
         switch(focus) {
-            case AUDIOFOCUS_NONE:
+            case AudioManager.AUDIOFOCUS_NONE:
                 return "none";
             case AudioManager.AUDIOFOCUS_GAIN:
                 return "GAIN";
@@ -118,6 +113,8 @@
                 return "GAIN_TRANSIENT";
             case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
                 return "GAIN_TRANSIENT_MAY_DUCK";
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
+                return "GAIN_TRANSIENT_EXCLUSIVE";
             case AudioManager.AUDIOFOCUS_LOSS:
                 return "LOSS";
             case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
@@ -178,21 +175,22 @@
                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                     case AudioManager.AUDIOFOCUS_LOSS:
-                    case AUDIOFOCUS_NONE:
+                    case AudioManager.AUDIOFOCUS_NONE:
                         return AudioManager.AUDIOFOCUS_LOSS;
                 }
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
             case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
                 switch(mFocusLossReceived) {
                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
-                    case AUDIOFOCUS_NONE:
+                    case AudioManager.AUDIOFOCUS_NONE:
                         return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
                     case AudioManager.AUDIOFOCUS_LOSS:
                         return AudioManager.AUDIOFOCUS_LOSS;
                 }
             case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
                 switch(mFocusLossReceived) {
-                    case AUDIOFOCUS_NONE:
+                    case AudioManager.AUDIOFOCUS_NONE:
                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                         return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
                     case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
@@ -202,7 +200,7 @@
                 }
             default:
                 Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest);
-                        return AUDIOFOCUS_NONE;
+                        return AudioManager.AUDIOFOCUS_NONE;
         }
     }
 
@@ -220,7 +218,7 @@
                 }
                 mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
             }
-            mFocusLossReceived = AUDIOFOCUS_NONE;
+            mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
         } catch (android.os.RemoteException e) {
             Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
         }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4a1646b..744e32a 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -119,6 +119,8 @@
     
     void unregisterAudioFocusClient(String clientId);
 
+    int getCurrentAudioFocus();
+
     oneway void dispatchMediaKeyEvent(in KeyEvent keyEvent);
     void dispatchMediaKeyEventUnderWakelock(in KeyEvent keyEvent);
 
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index c5b1101..ba2c63c 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -424,14 +424,20 @@
         }
     }
 
+    protected int getCurrentAudioFocus() {
+        synchronized(mAudioFocusLock) {
+            if (mFocusStack.empty()) {
+                return AudioManager.AUDIOFOCUS_NONE;
+            } else {
+                return mFocusStack.peek().getGainRequest();
+            }
+        }
+    }
 
     /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int)  */
     protected int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
             IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
         Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
-        // the main stream type for the audio focus request is currently not used. It may
-        // potentially be used to handle multiple stream type-dependent audio focuses.
-
         // we need a valid binder callback for clients
         if (!cb.pingBinder()) {
             Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 18e486d..665f3b1 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -34,7 +34,9 @@
     <string name="sort_name">By name</string>
     <string name="sort_date">By date modified</string>
 
-    <string name="drawer_open">Open navigation drawer</string>
-    <string name="drawer_close">Close navigation drawer</string>
+    <string name="drawer_open">Show roots</string>
+    <string name="drawer_close">Hide roots</string>
+
+    <string name="save_error">Failed to save document</string>
 
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 8b3dd99..1f22613 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -342,12 +342,15 @@
             final long lastModified = getCursorLong(cursor, DocumentColumns.LAST_MODIFIED);
             final int flags = getCursorInt(cursor, DocumentColumns.FLAGS);
 
+            final Uri uri = getArguments().getParcelable(EXTRA_URI);
+            final String authority = uri.getAuthority();
+
             if ((flags & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL) != 0) {
-                final Uri uri = getArguments().getParcelable(EXTRA_URI);
-                final Uri childUri = DocumentsContract.buildDocumentUri(uri.getAuthority(), guid);
+                final Uri childUri = DocumentsContract.buildDocumentUri(authority, guid);
                 icon.setImageURI(childUri);
             } else {
-                icon.setImageDrawable(DocumentsActivity.resolveDocumentIcon(context, mimeType));
+                icon.setImageDrawable(
+                        DocumentsActivity.resolveDocumentIcon(context, authority, mimeType));
             }
 
             title.setText(displayName);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 13def57..dcd02d2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -37,7 +37,10 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.database.Cursor;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -50,7 +53,9 @@
 import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
 import android.support.v4.widget.DrawerLayout.DrawerListener;
+import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Xml;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -66,11 +71,20 @@
 import android.widget.SearchView;
 import android.widget.SearchView.OnQueryTextListener;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
 
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 
 public class DocumentsActivity extends Activity {
@@ -92,7 +106,9 @@
     private DrawerLayout mDrawerLayout;
     private ActionBarDrawerToggle mDrawerToggle;
 
-    private ArrayList<Root> mRoots = Lists.newArrayList();
+    private static HashMap<String, DocumentsProviderInfo> sProviders = Maps.newHashMap();
+    private static ArrayList<Root> sRoots = Lists.newArrayList();
+
     private RootsAdapter mRootsAdapter;
     private ListView mRootsList;
 
@@ -142,7 +158,7 @@
         }
 
         mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
-        mRootsAdapter = new RootsAdapter(this, mRoots);
+        mRootsAdapter = new RootsAdapter(this, sRoots);
         mRootsList = (ListView) findViewById(R.id.roots_list);
         mRootsList.setAdapter(mRootsAdapter);
         mRootsList.setOnItemClickListener(mRootsListener);
@@ -406,9 +422,13 @@
         values.put(DocumentColumns.MIME_TYPE, mimeType);
         values.put(DocumentColumns.DISPLAY_NAME, displayName);
 
-        // TODO: handle errors from remote side
         final Uri uri = getContentResolver().insert(mCurrentDir, values);
-        onFinished(uri);
+        if (uri != null) {
+            onFinished(uri);
+        } else {
+            // TODO: ask for overwrite confirmation
+            Toast.makeText(this, R.string.save_error, Toast.LENGTH_SHORT).show();
+        }
     }
 
     private void onFinished(Uri... uris) {
@@ -448,37 +468,52 @@
     }
 
     public static class Root {
+        public DocumentsProviderInfo info;
         public int rootType;
         public Uri uri;
         public Drawable icon;
         public String title;
         public String summary;
 
-        public static Root fromCursor(Context context, ProviderInfo info, Cursor cursor) {
+        public static Root fromInfo(Context context, DocumentsProviderInfo info) {
             final Root root = new Root();
+            final PackageManager pm = context.getPackageManager();
+
+            root.info = info;
+            root.rootType = DocumentsContract.ROOT_TYPE_SERVICE;
+            root.uri = DocumentsContract.buildDocumentUri(
+                    info.providerInfo.authority, DocumentsContract.ROOT_GUID);
+            root.icon = info.providerInfo.loadIcon(pm);
+            root.title = info.providerInfo.loadLabel(pm).toString();
+            root.summary = null;
+
+            return root;
+        }
+
+        public static Root fromCursor(
+                Context context, DocumentsProviderInfo info, Cursor cursor) {
+            final Root root = fromInfo(context, info);
 
             root.rootType = cursor.getInt(cursor.getColumnIndex(RootColumns.ROOT_TYPE));
-            root.uri = DocumentsContract.buildDocumentUri(
-                    info.authority, cursor.getString(cursor.getColumnIndex(RootColumns.GUID)));
+            root.uri = DocumentsContract.buildDocumentUri(info.providerInfo.authority,
+                    cursor.getString(cursor.getColumnIndex(RootColumns.GUID)));
 
             final PackageManager pm = context.getPackageManager();
             final int icon = cursor.getInt(cursor.getColumnIndex(RootColumns.ICON));
             if (icon != 0) {
                 try {
-                    root.icon = pm.getResourcesForApplication(info.applicationInfo)
+                    root.icon = pm.getResourcesForApplication(info.providerInfo.applicationInfo)
                             .getDrawable(icon);
                 } catch (NotFoundException e) {
                     throw new RuntimeException(e);
                 } catch (NameNotFoundException e) {
                     throw new RuntimeException(e);
                 }
-            } else {
-                root.icon = info.loadIcon(pm);
             }
 
-            root.title = cursor.getString(cursor.getColumnIndex(RootColumns.TITLE));
-            if (root.title == null) {
-                root.title = info.loadLabel(pm).toString();
+            final String title = cursor.getString(cursor.getColumnIndex(RootColumns.TITLE));
+            if (title != null) {
+                root.title = title;
             }
 
             root.summary = cursor.getString(cursor.getColumnIndex(RootColumns.SUMMARY));
@@ -487,6 +522,17 @@
         }
     }
 
+    public static class DocumentsProviderInfo {
+        public ProviderInfo providerInfo;
+        public boolean customRoots;
+        public List<Icon> customIcons;
+    }
+
+    public static class Icon {
+        public String mimeType;
+        public Drawable icon;
+    }
+
     public static class Document {
         public Uri uri;
         public String mimeType;
@@ -541,8 +587,17 @@
         }
     }
 
-    public static Drawable resolveDocumentIcon(Context context, String mimeType) {
-        // TODO: allow backends to provide custom MIME icons
+    public static Drawable resolveDocumentIcon(Context context, String authority, String mimeType) {
+        // Custom icons take precedence
+        final DocumentsProviderInfo info = sProviders.get(authority);
+        if (info != null) {
+            for (Icon icon : info.customIcons) {
+                if (mimeMatches(icon.mimeType, mimeType)) {
+                    return icon.icon;
+                }
+            }
+        }
+
         if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) {
             return context.getResources().getDrawable(R.drawable.ic_dir);
         } else {
@@ -550,41 +605,112 @@
             final Intent intent = new Intent(Intent.ACTION_VIEW);
             intent.setType(mimeType);
 
-            final ResolveInfo info = pm.resolveActivity(
+            final ResolveInfo activityInfo = pm.resolveActivity(
                     intent, PackageManager.MATCH_DEFAULT_ONLY);
-            if (info != null) {
-                return info.loadIcon(pm);
+            if (activityInfo != null) {
+                return activityInfo.loadIcon(pm);
             } else {
                 return null;
             }
         }
     }
 
+    private static final String TAG_DOCUMENTS_PROVIDER = "documents-provider";
+    private static final String TAG_ICON = "icon";
+
     /**
      * Gather roots from all known storage providers.
      */
     private void updateRoots() {
-        mRoots.clear();
+        sProviders.clear();
+        sRoots.clear();
 
-        final List<ProviderInfo> providers = getPackageManager()
-                .queryContentProviders(null, -1, PackageManager.GET_META_DATA);
-        for (ProviderInfo info : providers) {
-            if (info.metaData != null
-                    && info.metaData.containsKey(DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
-                // TODO: populate roots on background thread, and cache results
-                final Uri uri = DocumentsContract.buildRootsUri(info.authority);
-                final Cursor cursor = getContentResolver().query(uri, null, null, null, null);
-                try {
-                    while (cursor.moveToNext()) {
-                        mRoots.add(Root.fromCursor(this, info, cursor));
+        final PackageManager pm = getPackageManager();
+        final List<ProviderInfo> providers = pm.queryContentProviders(
+                null, -1, PackageManager.GET_META_DATA);
+        for (ProviderInfo providerInfo : providers) {
+            if (providerInfo.metaData != null && providerInfo.metaData.containsKey(
+                    DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
+                final DocumentsProviderInfo info = parseInfo(this, providerInfo);
+                if (info == null) {
+                    Log.w(TAG, "Missing info for " + providerInfo);
+                    continue;
+                }
+
+                sProviders.put(info.providerInfo.authority, info);
+
+                if (info.customRoots) {
+                    // TODO: populate roots on background thread, and cache results
+                    final Uri uri = DocumentsContract.buildRootsUri(providerInfo.authority);
+                    final Cursor cursor = getContentResolver().query(uri, null, null, null, null);
+                    try {
+                        while (cursor.moveToNext()) {
+                            sRoots.add(Root.fromCursor(this, info, cursor));
+                        }
+                    } finally {
+                        cursor.close();
                     }
-                } finally {
-                    cursor.close();
+                } else if (info != null) {
+                    sRoots.add(Root.fromInfo(this, info));
                 }
             }
         }
     }
 
+    private static DocumentsProviderInfo parseInfo(Context context, ProviderInfo providerInfo) {
+        final DocumentsProviderInfo info = new DocumentsProviderInfo();
+        info.providerInfo = providerInfo;
+        info.customIcons = Lists.newArrayList();
+
+        final PackageManager pm = context.getPackageManager();
+        final Resources res;
+        try {
+            res = pm.getResourcesForApplication(providerInfo.applicationInfo);
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Failed to find resources for " + providerInfo, e);
+            return null;
+        }
+
+        XmlResourceParser parser = null;
+        try {
+            parser = providerInfo.loadXmlMetaData(
+                    pm, DocumentsContract.META_DATA_DOCUMENT_PROVIDER);
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            int type = 0;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                final String tag = parser.getName();
+                if (type == XmlPullParser.START_TAG && TAG_DOCUMENTS_PROVIDER.equals(tag)) {
+                    final TypedArray a = res.obtainAttributes(
+                            attrs, com.android.internal.R.styleable.DocumentsProviderInfo);
+                    info.customRoots = a.getBoolean(
+                            com.android.internal.R.styleable.DocumentsProviderInfo_customRoots,
+                            false);
+                    a.recycle();
+
+                } else if (type == XmlPullParser.START_TAG && TAG_ICON.equals(tag)) {
+                    final TypedArray a = res.obtainAttributes(
+                            attrs, com.android.internal.R.styleable.Icon);
+                    final Icon icon = new Icon();
+                    icon.mimeType = a.getString(com.android.internal.R.styleable.Icon_mimeType);
+                    icon.icon = a.getDrawable(com.android.internal.R.styleable.Icon_icon);
+                    info.customIcons.add(icon);
+                    a.recycle();
+                }
+            }
+        } catch (IOException e){
+            Log.w(TAG, "Failed to parse metadata", e);
+            return null;
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "Failed to parse metadata", e);
+            return null;
+        } finally {
+            IoUtils.closeQuietly(parser);
+        }
+
+        return info;
+    }
+
     private OnItemClickListener mRootsListener = new OnItemClickListener() {
         @Override
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index a2a4f7c..cdc399d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -66,7 +66,7 @@
 
         final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
         icon.setImageDrawable(DocumentsActivity.resolveDocumentIcon(
-                context, getArguments().getString(EXTRA_MIME_TYPE)));
+                context, null, getArguments().getString(EXTRA_MIME_TYPE)));
 
         mDisplayName = (EditText) view.findViewById(android.R.id.title);
         mDisplayName.setText(getArguments().getString(EXTRA_DISPLAY_NAME));
diff --git a/packages/ExternalStorageProvider/AndroidManifest.xml b/packages/ExternalStorageProvider/AndroidManifest.xml
index 37dc5b1..afdb6bb 100644
--- a/packages/ExternalStorageProvider/AndroidManifest.xml
+++ b/packages/ExternalStorageProvider/AndroidManifest.xml
@@ -13,7 +13,7 @@
             android:permission="android.permission.MANAGE_DOCUMENTS">
             <meta-data
                 android:name="android.content.DOCUMENT_PROVIDER"
-                android:value="true" />
+                android:resource="@xml/document_provider" />
         </provider>
     </application>
 </manifest>
diff --git a/packages/ExternalStorageProvider/res/drawable-hdpi/ic_pdf.png b/packages/ExternalStorageProvider/res/drawable-hdpi/ic_pdf.png
new file mode 100644
index 0000000..961a9bb
--- /dev/null
+++ b/packages/ExternalStorageProvider/res/drawable-hdpi/ic_pdf.png
Binary files differ
diff --git a/packages/ExternalStorageProvider/res/xml/document_provider.xml b/packages/ExternalStorageProvider/res/xml/document_provider.xml
new file mode 100644
index 0000000..929a273
--- /dev/null
+++ b/packages/ExternalStorageProvider/res/xml/document_provider.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<documents-provider xmlns:android="http://schemas.android.com/apk/res/android"
+    android:customRoots="true">
+
+    <icon android:mimeType="application/pdf" android:icon="@drawable/ic_pdf" />
+    <icon android:mimeType="text/*" android:icon="@drawable/ic_pdf" />
+</documents-provider>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 459c92c..26f910e 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2985,6 +2985,13 @@
                         mActionBar.initIndeterminateProgress();
                     }
 
+                    final ActionBarOverlayLayout abol = (ActionBarOverlayLayout) findViewById(
+                            com.android.internal.R.id.action_bar_overlay_layout);
+                    if (abol != null) {
+                        abol.setOverlayMode(
+                                (localFeatures & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0);
+                    }
+
                     boolean splitActionBar = false;
                     final boolean splitWhenNarrow =
                             (mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0;
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index 6b4d248..b2d8b94 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -64,6 +64,8 @@
     // Write at most every 30 minutes.
     static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
 
+    static final int CURRENT_VERSION = 1;
+
     Context mContext;
     final AtomicFile mFile;
     final Handler mHandler;
@@ -704,6 +706,9 @@
                         throw new IllegalStateException("no start tag found");
                     }
 
+                    String versStr = parser.getAttributeValue(null, "vers");
+                    int vers = versStr != null ? Integer.parseInt(versStr) : 0;
+
                     int outerDepth = parser.getDepth();
                     while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                             && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -713,7 +718,7 @@
 
                         String tagName = parser.getName();
                         if (tagName.equals("pkg")) {
-                            readPackage(parser);
+                            readPackage(parser, vers);
                         } else {
                             Slog.w(TAG, "Unknown element under <app-ops>: "
                                     + parser.getName());
@@ -746,7 +751,7 @@
         }
     }
 
-    void readPackage(XmlPullParser parser) throws NumberFormatException,
+    void readPackage(XmlPullParser parser, int vers) throws NumberFormatException,
             XmlPullParserException, IOException {
         String pkgName = parser.getAttributeValue(null, "n");
         int outerDepth = parser.getDepth();
@@ -759,7 +764,7 @@
 
             String tagName = parser.getName();
             if (tagName.equals("uid")) {
-                readUid(parser, pkgName);
+                readUid(parser, vers, pkgName);
             } else {
                 Slog.w(TAG, "Unknown element under <pkg>: "
                         + parser.getName());
@@ -768,7 +773,7 @@
         }
     }
 
-    void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
+    void readUid(XmlPullParser parser, int vers, String pkgName) throws NumberFormatException,
             XmlPullParserException, IOException {
         int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
         int outerDepth = parser.getDepth();
@@ -784,7 +789,12 @@
                 Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
                 String mode = parser.getAttributeValue(null, "m");
                 if (mode != null) {
-                    op.mode = Integer.parseInt(mode);
+                    if (vers < CURRENT_VERSION && op.op != AppOpsManager.OP_POST_NOTIFICATION) {
+                        Slog.w(TAG, "AppOps vers " + vers + ": drop mode from "
+                                + pkgName + "/" + uid + " op " + op.op);
+                    } else {
+                        op.mode = Integer.parseInt(mode);
+                    }
                 }
                 String time = parser.getAttributeValue(null, "t");
                 if (time != null) {
@@ -834,6 +844,7 @@
                 out.setOutput(stream, "utf-8");
                 out.startDocument(null, true);
                 out.startTag(null, "app-ops");
+                out.attribute(null, "vers", Integer.toString(CURRENT_VERSION));
 
                 if (allOps != null) {
                     String lastPkg = null;
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index dfaafb8..cde84dc 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -117,6 +117,9 @@
 
     private static final long NANOS_PER_MILLI = 1000000L;
 
+    // The maximum interval a location request can have and still be considered "high power".
+    private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
+
     // 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
@@ -459,16 +462,20 @@
         final ILocationListener mListener;
         final PendingIntent mPendingIntent;
         final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
+        final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
         final Object mKey;
 
         final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
 
+        // True if app ops has started monitoring this receiver for locations.
         boolean mOpMonitoring;
+        // True if app ops has started monitoring this receiver for high power (gps) locations.
+        boolean mOpHighPowerMonitoring;
         int mPendingBroadcasts;
         PowerManager.WakeLock mWakeLock;
 
         Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
-                String packageName, WorkSource workSource) {
+                String packageName, WorkSource workSource, boolean hideFromAppOps) {
             mListener = listener;
             mPendingIntent = intent;
             if (listener != null) {
@@ -484,6 +491,7 @@
                 workSource = null;
             }
             mWorkSource = workSource;
+            mHideFromAppOps = hideFromAppOps;
 
             updateMonitoring(true);
 
@@ -526,18 +534,52 @@
         }
 
         public void updateMonitoring(boolean allow) {
-            if (!mOpMonitoring) {
-                if (allow) {
-                    mOpMonitoring = mAppOps.startOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
-                            mUid, mPackageName) == AppOpsManager.MODE_ALLOWED;
-                }
-            } else {
-                if (!allow || mAppOps.checkOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
-                        mUid, mPackageName) != AppOpsManager.MODE_ALLOWED) {
-                    mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, mUid, mPackageName);
-                    mOpMonitoring = false;
+            if (mHideFromAppOps) {
+                return;
+            }
+
+            // First update monitoring of any location request (including high power).
+            mOpMonitoring = updateMonitoring(allow, mOpMonitoring,
+                    AppOpsManager.OP_MONITOR_LOCATION);
+
+            // Now update monitoring of high power requests only.
+            // A high power request is any gps request with interval under a threshold.
+            boolean allowHighPower = allow;
+            if (allowHighPower) {
+                UpdateRecord gpsRecord = mUpdateRecords.get(LocationManager.GPS_PROVIDER);
+                if (gpsRecord == null
+                        || gpsRecord.mRequest.getInterval() > HIGH_POWER_INTERVAL_MS) {
+                    allowHighPower = false;
                 }
             }
+            mOpHighPowerMonitoring = updateMonitoring(allowHighPower, mOpHighPowerMonitoring,
+                    AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
+        }
+
+        /**
+         * Update AppOps monitoring for a single location request and op type.
+         *
+         * @param allowMonitoring True if monitoring is allowed for this request/op.
+         * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
+         * @param op AppOps code for the op to update.
+         * @return True if monitoring is on for this request/op after updating.
+         */
+        private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
+                int op) {
+            if (!currentlyMonitoring) {
+                if (allowMonitoring) {
+                    return mAppOps.startOpNoThrow(op, mUid, mPackageName)
+                            == AppOpsManager.MODE_ALLOWED;
+                }
+            } else {
+                if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
+                        != AppOpsManager.MODE_ALLOWED) {
+                    mAppOps.finishOp(op, mUid, mPackageName);
+                    return false;
+                }
+            }
+
+            return currentlyMonitoring;
         }
 
         public boolean isListener() {
@@ -895,11 +937,16 @@
      * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
      * for battery).
      */
-    private void checkWorkSourceAllowed() {
+    private void checkDeviceStatsAllowed() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
     }
 
+    private void checkUpdateAppOpsAllowed() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
+    }
+
     public static int resolutionLevelToOp(int allowedResolutionLevel) {
         if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
             if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
@@ -1224,11 +1271,12 @@
     }
 
     private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
-            String packageName, WorkSource workSource) {
+            String packageName, WorkSource workSource, boolean hideFromAppOps) {
         IBinder binder = listener.asBinder();
         Receiver receiver = mReceivers.get(binder);
         if (receiver == null) {
-            receiver = new Receiver(listener, null, pid, uid, packageName, workSource);
+            receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
+                    hideFromAppOps);
             mReceivers.put(binder, receiver);
 
             try {
@@ -1242,10 +1290,11 @@
     }
 
     private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
-            WorkSource workSource) {
+            WorkSource workSource, boolean hideFromAppOps) {
         Receiver receiver = mReceivers.get(intent);
         if (receiver == null) {
-            receiver = new Receiver(null, intent, pid, uid, packageName, workSource);
+            receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
+                    hideFromAppOps);
             mReceivers.put(intent, receiver);
         }
         return receiver;
@@ -1307,16 +1356,16 @@
     }
 
     private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
-            int pid, int uid, String packageName, WorkSource workSource) {
+            int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
         if (intent == null && listener == null) {
             throw new IllegalArgumentException("need either listener or intent");
         } else if (intent != null && listener != null) {
             throw new IllegalArgumentException("cannot register both listener and intent");
         } else if (intent != null) {
             checkPendingIntent(intent);
-            return getReceiverLocked(intent, pid, uid, packageName, workSource);
+            return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
         } else {
-            return getReceiverLocked(listener, pid, uid, packageName, workSource);
+            return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
         }
     }
 
@@ -1330,7 +1379,11 @@
                 request.getProvider());
         WorkSource workSource = request.getWorkSource();
         if (workSource != null && workSource.size() > 0) {
-            checkWorkSourceAllowed();
+            checkDeviceStatsAllowed();
+        }
+        boolean hideFromAppOps = request.getHideFromAppOps();
+        if (hideFromAppOps) {
+            checkUpdateAppOpsAllowed();
         }
         LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
 
@@ -1345,7 +1398,7 @@
 
             synchronized (mLock) {
                 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
-                        packageName, workSource);
+                        packageName, workSource, hideFromAppOps);
                 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
             }
         } finally {
@@ -1383,6 +1436,9 @@
             // Notify the listener that updates are currently disabled
             receiver.callProviderEnabledLocked(name, false);
         }
+        // Update the monitoring here just in case multiple location requests were added to the
+        // same receiver (this request may be high power and the initial might not have been).
+        receiver.updateMonitoring(true);
     }
 
     @Override
@@ -1395,8 +1451,9 @@
 
         synchronized (mLock) {
             WorkSource workSource = null;
-            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName,
-                    workSource);
+            boolean hideFromAppOps = false;
+            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
+                    packageName, workSource, hideFromAppOps);
 
             // providers may use public location API's, need to clear identity
             long identity = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index bdf6129..1e8a5899 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -1633,7 +1633,7 @@
             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
         }
         checkCallerIsSystemOrSameApp(pkg);
-        final boolean isSystemNotification = isCallerSystem() || ("android".equals(pkg));
+        final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
 
         final int userId = ActivityManager.handleIncomingUser(callingPid,
                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
@@ -1873,9 +1873,9 @@
                             }
                             mSoundNotification = r;
                             // do not play notifications if stream volume is 0 (typically because
-                            // ringer mode is silent) or if speech recognition is active.
+                            // ringer mode is silent) or if there is a user of exclusive audio focus
                             if ((audioManager.getStreamVolume(audioStreamType) != 0)
-                                    && !audioManager.isSpeechRecognitionActive()) {
+                                    && !audioManager.isAudioFocusExclusive()) {
                                 final long identity = Binder.clearCallingIdentity();
                                 try {
                                     final IRingtonePlayer player = mAudioService.getRingtonePlayer();
@@ -2151,14 +2151,18 @@
         cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId);
     }
 
-    // Return true if the caller is a system or phone UID and therefore should not have
+    // Return true if the UID is a system or phone UID and therefore should not have
     // any notifications or toasts blocked.
-    boolean isCallerSystem() {
-        final int uid = Binder.getCallingUid();
+    boolean isUidSystem(int uid) {
         final int appid = UserHandle.getAppId(uid);
         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
     }
 
+    // same as isUidSystem(int, int) for the Binder caller's UID.
+    boolean isCallerSystem() {
+        return isUidSystem(Binder.getCallingUid());
+    }
+
     void checkCallerIsSystem() {
         if (isCallerSystem()) {
             return;
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java
index 066e35c..fe4d602 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegion2Activity.java
@@ -48,7 +48,7 @@
     }
 
     public static class RegionView extends FrameLayout {
-        private final Region mRegion = new Region();
+        private Region mRegion = new Region();
         private float mClipPosition = 0.0f;
 
         public RegionView(Context c) {
@@ -69,9 +69,7 @@
 
             canvas.save();
 
-            mRegion.setEmpty();
-            mRegion.op(0, 0, getWidth(), getHeight(),
-                    Region.Op.REPLACE);
+            mRegion.set(0, 0, getWidth(), getHeight());
             mRegion.op(getWidth() / 4, getHeight() / 4, 3 * getWidth() / 4, 3 * getHeight() / 4,
                     Region.Op.DIFFERENCE);