Merge "Cache media/nomedia paths"
diff --git a/Android.mk b/Android.mk
index 781d5d1..0865d24 100644
--- a/Android.mk
+++ b/Android.mk
@@ -89,6 +89,8 @@
 	core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreSession.aidl \
+	core/java/android/app/maintenance/IIdleCallback.aidl \
+	core/java/android/app/maintenance/IIdleService.aidl \
 	core/java/android/bluetooth/IBluetooth.aidl \
 	core/java/android/bluetooth/IBluetoothA2dp.aidl \
 	core/java/android/bluetooth/IBluetoothCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 1ec7f08..c0ed81a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -543,6 +543,7 @@
     field public static final int fromAlpha = 16843210; // 0x10101ca
     field public static final int fromDegrees = 16843187; // 0x10101b3
     field public static final int fromScene = 16843741; // 0x10103dd
+    field public static final int fromSceneName = 16843774; // 0x10103fe
     field public static final int fromXDelta = 16843206; // 0x10101c6
     field public static final int fromXScale = 16843202; // 0x10101c2
     field public static final int fromYDelta = 16843208; // 0x10101c8
@@ -960,6 +961,7 @@
     field public static final int shadowRadius = 16843108; // 0x1010164
     field public static final int shape = 16843162; // 0x101019a
     field public static final int shareInterpolator = 16843195; // 0x10101bb
+    field public static final int sharedElementName = 16843776; // 0x1010400
     field public static final int sharedUserId = 16842763; // 0x101000b
     field public static final int sharedUserLabel = 16843361; // 0x1010261
     field public static final int shouldDisableView = 16843246; // 0x10101ee
@@ -1142,6 +1144,7 @@
     field public static final int toAlpha = 16843211; // 0x10101cb
     field public static final int toDegrees = 16843188; // 0x10101b4
     field public static final int toScene = 16843742; // 0x10103de
+    field public static final int toSceneName = 16843775; // 0x10103ff
     field public static final int toXDelta = 16843207; // 0x10101c7
     field public static final int toXScale = 16843203; // 0x10101c3
     field public static final int toYDelta = 16843209; // 0x10101c9
@@ -1157,6 +1160,7 @@
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
     field public static final int transition = 16843743; // 0x10103df
+    field public static final int transitionGroup = 16843777; // 0x1010401
     field public static final int transitionOrdering = 16843744; // 0x10103e0
     field public static final int translationX = 16843554; // 0x1010322
     field public static final int translationY = 16843555; // 0x1010323
@@ -1514,6 +1518,7 @@
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
     field public static final int selectedIcon = 16908302; // 0x102000e
+    field public static final int shared_element_name = 16908334; // 0x102002e
     field public static final int startSelectingText = 16908328; // 0x1020028
     field public static final int stopSelectingText = 16908329; // 0x1020029
     field public static final int summary = 16908304; // 0x1020010
@@ -3035,6 +3040,7 @@
     method public int getTaskId();
     method public final java.lang.CharSequence getTitle();
     method public final int getTitleColor();
+    method public android.os.Bundle getTransitionArgs();
     method public final int getVolumeControlStream();
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
@@ -3130,6 +3136,7 @@
     method public void setContentView(android.view.View);
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public final void setDefaultKeyMode(int);
+    method public void setEarlyBackgroundTransition(boolean);
     method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable);
     method public final void setFeatureDrawableAlpha(int, int);
     method public final void setFeatureDrawableResource(int, int);
@@ -3170,6 +3177,7 @@
     method public boolean startNextMatchingActivity(android.content.Intent);
     method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+    method protected void startSharedElementTransition(android.os.Bundle);
     method public deprecated void stopManagingCursor(android.database.Cursor);
     method public void takeKeyEvents(boolean);
     method public void triggerSearch(java.lang.String, android.os.Bundle);
@@ -3340,6 +3348,7 @@
   public class ActivityOptions {
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
     method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
+    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.os.Bundle);
     method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
@@ -3349,8 +3358,11 @@
     ctor public ActivityView(android.content.Context);
     ctor public ActivityView(android.content.Context, android.util.AttributeSet);
     ctor public ActivityView(android.content.Context, android.util.AttributeSet, int);
+    method public boolean isAttachedToDisplay();
     method protected void onLayout(boolean, int, int, int, int);
     method public void startActivity(android.content.Intent);
+    method public void startActivity(android.content.IntentSender);
+    method public void startActivity(android.app.PendingIntent);
   }
 
   public class AlarmManager {
@@ -4886,6 +4898,20 @@
 
 }
 
+package android.app.maintenance {
+
+  public abstract class IdleService extends android.app.Service {
+    ctor public IdleService();
+    method public final void finishIdle();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract boolean onIdleStart();
+    method public abstract void onIdleStop();
+    field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_IDLE_SERVICE";
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.idle.IdleService";
+  }
+
+}
+
 package android.appwidget {
 
   public class AppWidgetHost {
@@ -6187,6 +6213,7 @@
     method public abstract android.content.ContentResolver getContentResolver();
     method public abstract java.io.File getDatabasePath(java.lang.String);
     method public abstract java.io.File getDir(java.lang.String, int);
+    method public final android.graphics.drawable.Drawable getDrawable(int);
     method public abstract java.io.File getExternalCacheDir();
     method public abstract java.io.File[] getExternalCacheDirs();
     method public abstract java.io.File getExternalFilesDir(java.lang.String);
@@ -7998,7 +8025,9 @@
     method public int getDimensionPixelSize(int) throws android.content.res.Resources.NotFoundException;
     method public android.util.DisplayMetrics getDisplayMetrics();
     method public android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
+    method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
+    method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
     method public float getFraction(int, int, int);
     method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
     method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException;
@@ -8042,6 +8071,7 @@
   public final class Resources.Theme {
     method public void applyStyle(int, boolean);
     method public void dump(int, java.lang.String, java.lang.String);
+    method public android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet, int[], int, int);
@@ -10349,6 +10379,7 @@
     ctor public BitmapDrawable(android.content.res.Resources, java.lang.String);
     ctor public deprecated BitmapDrawable(java.io.InputStream);
     ctor public BitmapDrawable(android.content.res.Resources, java.io.InputStream);
+    method public void draw(android.graphics.Canvas);
     method public final android.graphics.Bitmap getBitmap();
     method public final android.graphics.drawable.Drawable.ConstantState getConstantState();
     method public int getGravity();
@@ -10374,6 +10405,7 @@
 
   public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public ClipDrawable(android.graphics.drawable.Drawable, int, int);
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -10387,6 +10419,7 @@
   public class ColorDrawable extends android.graphics.drawable.Drawable {
     ctor public ColorDrawable();
     ctor public ColorDrawable(int);
+    method public void draw(android.graphics.Canvas);
     method public int getColor();
     method public int getOpacity();
     method public void setAlpha(int);
@@ -10405,7 +10438,7 @@
     method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, java.lang.String);
     method public static android.graphics.drawable.Drawable createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.graphics.drawable.Drawable createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas);
+    method public abstract void draw(android.graphics.Canvas);
     method public int getAlpha();
     method public final android.graphics.Rect getBounds();
     method public android.graphics.drawable.Drawable.Callback getCallback();
@@ -10429,7 +10462,6 @@
     method public void jumpToCurrentState();
     method public android.graphics.drawable.Drawable mutate();
     method protected void onBoundsChange(android.graphics.Rect);
-    method protected void onDraw(android.graphics.Canvas);
     method protected boolean onLevelChange(int);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
@@ -10465,6 +10497,7 @@
 
   public class DrawableContainer extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public DrawableContainer();
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -10505,6 +10538,7 @@
   public class GradientDrawable extends android.graphics.drawable.Drawable {
     ctor public GradientDrawable();
     ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
     method public boolean onStateChange(int[]);
@@ -10551,6 +10585,7 @@
   public class InsetDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
+    method public void draw(android.graphics.Canvas);
     method public android.graphics.drawable.Drawable getDrawable();
     method public int getOpacity();
     method public void invalidateDrawable(android.graphics.drawable.Drawable);
@@ -10562,6 +10597,7 @@
 
   public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
+    method public void draw(android.graphics.Canvas);
     method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
     method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getId(int);
@@ -10592,6 +10628,7 @@
     ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
     ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
     ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public android.graphics.Paint getPaint();
     method public void setAlpha(int);
@@ -10610,6 +10647,7 @@
 
   public class PictureDrawable extends android.graphics.drawable.Drawable {
     ctor public PictureDrawable(android.graphics.Picture);
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public android.graphics.Picture getPicture();
     method public void setAlpha(int);
@@ -10623,17 +10661,32 @@
 
   public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public RotateDrawable();
+    method public void draw(android.graphics.Canvas);
     method public android.graphics.drawable.Drawable getDrawable();
+    method public float getFromDegrees();
     method public int getOpacity();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getToDegrees();
     method public void invalidateDrawable(android.graphics.drawable.Drawable);
+    method public boolean isPivotXRelative();
+    method public boolean isPivotYRelative();
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setFromDegrees(float);
+    method public void setPivotX(float);
+    method public void setPivotXRelative(boolean);
+    method public void setPivotY(float);
+    method public void setPivotYRelative(boolean);
+    method public void setToDegrees(float);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
   public class ScaleDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public ScaleDrawable(android.graphics.drawable.Drawable, int, float, float);
+    method public void draw(android.graphics.Canvas);
     method public android.graphics.drawable.Drawable getDrawable();
     method public int getOpacity();
     method public void invalidateDrawable(android.graphics.drawable.Drawable);
@@ -10646,6 +10699,7 @@
   public class ShapeDrawable extends android.graphics.drawable.Drawable {
     ctor public ShapeDrawable();
     ctor public ShapeDrawable(android.graphics.drawable.shapes.Shape);
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public android.graphics.Paint getPaint();
     method public android.graphics.drawable.ShapeDrawable.ShaderFactory getShaderFactory();
@@ -18333,7 +18387,7 @@
 
   public abstract class CountDownTimer {
     ctor public CountDownTimer(long, long);
-    method public final void cancel();
+    method public final synchronized void cancel();
     method public abstract void onFinish();
     method public abstract void onTick(long);
     method public final synchronized android.os.CountDownTimer start();
@@ -26637,6 +26691,7 @@
     method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
     method public android.transition.Transition addTarget(int);
     method public android.transition.Transition addTarget(android.view.View);
+    method public boolean canRemoveViews();
     method public abstract void captureEndValues(android.transition.TransitionValues);
     method public abstract void captureStartValues(android.transition.TransitionValues);
     method public android.transition.Transition clone();
@@ -28701,6 +28756,7 @@
     method public int getScrollBarStyle();
     method public final int getScrollX();
     method public final int getScrollY();
+    method public java.lang.String getSharedElementName();
     method public int getSolidColor();
     method protected int getSuggestedMinimumHeight();
     method protected int getSuggestedMinimumWidth();
@@ -28954,6 +29010,7 @@
     method public void setScrollY(int);
     method public void setScrollbarFadingEnabled(boolean);
     method public void setSelected(boolean);
+    method public void setSharedElementName(java.lang.String);
     method public void setSoundEffectsEnabled(boolean);
     method public void setSystemUiVisibility(int);
     method public void setTag(java.lang.Object);
@@ -29340,6 +29397,7 @@
     method protected boolean isChildrenDrawingOrderEnabled();
     method protected boolean isChildrenDrawnWithCacheEnabled();
     method public boolean isMotionEventSplittingEnabled();
+    method public boolean isTransitionGroup();
     method public final void layout(int, int, int, int);
     method protected void measureChild(android.view.View, int, int);
     method protected void measureChildWithMargins(android.view.View, int, int, int, int);
@@ -29385,6 +29443,7 @@
     method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
     method public void setPersistentDrawingCache(int);
     method protected void setStaticTransformationsEnabled(boolean);
+    method public void setTransitionGroup(boolean);
     method public boolean shouldDelayChildPressedState();
     method public boolean showContextMenuForChild(android.view.View);
     method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
@@ -29679,7 +29738,6 @@
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract deprecated void setTitleColor(int);
     method public void setTransitionManager(android.transition.TransitionManager);
-    method public void setTransitionOptions(android.os.Bundle);
     method public void setType(int);
     method public void setUiOptions(int);
     method public void setUiOptions(int, int);
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index bfbae24..242b3ea 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -100,7 +100,7 @@
             try {
                 AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
                 Context authContext = createPackageContext(desc.packageName, 0);
-                icon = authContext.getResources().getDrawable(desc.iconId);
+                icon = authContext.getDrawable(desc.iconId);
             } catch (PackageManager.NameNotFoundException e) {
                 // Nothing we can do much here, just log
                 if (Log.isLoggable(TAG, Log.WARN)) {
diff --git a/core/java/android/accounts/ChooseAccountTypeActivity.java b/core/java/android/accounts/ChooseAccountTypeActivity.java
index acc8549..a3222d8 100644
--- a/core/java/android/accounts/ChooseAccountTypeActivity.java
+++ b/core/java/android/accounts/ChooseAccountTypeActivity.java
@@ -129,7 +129,7 @@
             Drawable icon = null;
             try {
                 Context authContext = createPackageContext(desc.packageName, 0);
-                icon = authContext.getResources().getDrawable(desc.iconId);
+                icon = authContext.getDrawable(desc.iconId);
                 final CharSequence sequence = authContext.getResources().getText(desc.labelId);
                 if (sequence != null) {
                     name = sequence.toString();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 698f06a..a8716bf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.transition.Scene;
-import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
 import android.util.SuperNotCalledException;
@@ -771,6 +770,7 @@
 
     private Thread mUiThread;
     final Handler mHandler = new Handler();
+    private ActivityOptions mTransitionActivityOptions;
 
     /** Return the intent that started this activity. */
     public Intent getIntent() {
@@ -3443,38 +3443,16 @@
      *
      * @throws android.content.ActivityNotFoundException
      *
-     * @see #startActivity 
+     * @see #startActivity
      */
     public void startActivityForResult(Intent intent, int requestCode) {
-        final TransitionManager tm = getWindow().getTransitionManager();
-        final Scene currScene = getWindow().getContentScene();
-        final String[] targetSceneNames = currScene != null && tm != null ?
-                tm.getTargetSceneNames(currScene) : null;
-
-        if (targetSceneNames == null || targetSceneNames.length == 0) {
-            startActivityForResult(intent, requestCode, null);
-        } else {
-            // TODO Capture the scene transition args and send along
-            final ActivityOptions opts = ActivityOptions.makeSceneTransitionAnimation(
-                    targetSceneNames, null,
-                    new ActivityOptions.OnSceneTransitionStartedListener() {
-                        @Override public void onSceneTransitionStarted(String destSceneName) {
-                            final Transition t = tm.getNamedTransition(currScene, destSceneName);
-                            // TODO Fill this in to notify the outgoing activity that it should
-                            // treat this as a sync point for the transition - the target
-                            // transition has started.
-                            Log.d(TAG, "Scene transition to scene " + destSceneName +
-                                    " transition " + t);
-                        }
-                    }, mHandler);
-            startActivityForResult(intent, requestCode, opts.toBundle());
-        }
+        startActivityForResult(intent, requestCode, null);
     }
 
     /**
      * Launch an activity for which you would like a result when it finished.
      * When this activity exits, your
-     * onActivityResult() method will be called with the given requestCode. 
+     * onActivityResult() method will be called with the given requestCode.
      * Using a negative requestCode is the same as calling 
      * {@link #startActivity} (the activity is not launched as a sub-activity).
      *
@@ -3487,9 +3465,9 @@
      *
      * <p>As a special case, if you call startActivityForResult() with a requestCode 
      * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your
-     * activity, then your window will not be displayed until a result is 
-     * returned back from the started activity.  This is to avoid visible 
-     * flickering when redirecting to another activity. 
+     * activity, then your window will not be displayed until a result is
+     * returned back from the started activity.  This is to avoid visible
+     * flickering when redirecting to another activity.
      *
      * <p>This method throws {@link android.content.ActivityNotFoundException}
      * if there was no Activity found to run the given Intent.
@@ -3503,9 +3481,17 @@
      *
      * @throws android.content.ActivityNotFoundException
      *
-     * @see #startActivity 
+     * @see #startActivity
      */
     public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
+        TransitionManager tm = getContentTransitionManager();
+        if (tm != null && options != null) {
+            ActivityOptions activityOptions = new ActivityOptions(options);
+            if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+                getWindow().startExitTransition(activityOptions);
+                options = activityOptions.toBundle();
+            }
+        }
         if (mParent == null) {
             Instrumentation.ActivityResult ar =
                 mInstrumentation.execStartActivity(
@@ -5313,7 +5299,7 @@
             mWindow.setUiOptions(info.uiOptions);
         }
         mUiThread = Thread.currentThread();
-        
+
         mMainThread = aThread;
         mInstrumentation = instr;
         mToken = token;
@@ -5335,8 +5321,40 @@
             mWindow.setContainer(mParent.getWindow());
         }
         mWindowManager = mWindow.getWindowManager();
-        mWindow.setTransitionOptions(options);
         mCurrentConfig = config;
+        mTransitionActivityOptions = null;
+        Window.SceneTransitionListener sceneTransitionListener = null;
+        if (options != null) {
+            ActivityOptions activityOptions = new ActivityOptions(options);
+            if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+                mTransitionActivityOptions = activityOptions;
+                sceneTransitionListener = new Window.SceneTransitionListener() {
+                    @Override
+                    public void enterSharedElement(Bundle transitionArgs) {
+                        startSharedElementTransition(transitionArgs);
+                        mTransitionActivityOptions = null;
+                    }
+
+                    @Override
+                    public void nullPendingTransition() {
+                        overridePendingTransition(0, 0);
+                    }
+
+                    @Override
+                    public void convertFromTranslucent() {
+                        Activity.this.convertFromTranslucent();
+                    }
+
+                    @Override
+                    public void convertToTranslucent() {
+                        Activity.this.convertToTranslucent(null);
+                    }
+                };
+
+            }
+        }
+
+        mWindow.setTransitionOptions(mTransitionActivityOptions, sceneTransitionListener);
     }
 
     /** @hide */
@@ -5350,7 +5368,7 @@
                 com.android.internal.R.styleable.Window_windowNoDisplay, false);
         mFragments.dispatchActivityCreated();
     }
-    
+
     final void performStart() {
         mFragments.noteStateNotSaved();
         mCalled = false;
@@ -5507,7 +5525,7 @@
                     }
                 }
             }
-    
+
             mStopped = true;
         }
         mResumed = false;
@@ -5522,7 +5540,57 @@
             mLoaderManager.doDestroy();
         }
     }
-    
+
+    /**
+     * Gets the entering Activity transition args. Will be null if
+     * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)} was
+     * not used to pass a Bundle to startActivity. The Bundle passed to that method in the
+     * calling Activity is returned here.
+     * <p>After startSharedElementTransition is called, this method will return null.</p>
+     *
+     * @return The Bundle passed into Bundle parameter of
+     *         {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)}
+     *         in the calling Activity.
+     */
+    public Bundle getTransitionArgs() {
+        if (mTransitionActivityOptions == null) {
+            return null;
+        }
+        return mTransitionActivityOptions.getSceneTransitionArgs();
+    }
+
+    /**
+     * Override to transfer a shared element from a calling Activity to this Activity.
+     * Shared elements will be made VISIBLE before this call. The Activity is responsible
+     * for transitioning the shared elements from their location to the eventual destination.
+     * The shared element will be laid out a the destination when this method is called.
+     *
+     * @param transitionArgs The same as returned from {@link #getTransitionArgs()}, this should
+     *                       contain information from the calling Activity to tell where the
+     *                       shared element should be placed.
+     */
+    protected void startSharedElementTransition(Bundle transitionArgs) {
+    }
+
+    /**
+     * Controls how the background fade is triggered when there is an entering Activity transition.
+     * If fadeEarly is true, the Window background will fade in as soon as the shared elements are
+     * ready to switch. If fadeEarly is false, the background will fade only after the calling
+     * Activity's exit transition completes. By default, the Window will fade in when the calling
+     * Activity's exit transition completes.
+     *
+     * @param fadeEarly Set to true to fade out the exiting Activity as soon as the shared elements
+     *                  are transferred. Set to false to fade out the exiting Activity as soon as
+     *                  the shared element is transferred.
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     */
+    public void setEarlyBackgroundTransition(boolean fadeEarly) {
+        if (mTransitionActivityOptions == null) {
+            return;
+        }
+        mWindow.setEarlyBackgroundTransition(fadeEarly);
+    }
+
     /**
      * @hide
      */
@@ -5530,7 +5598,7 @@
         return mResumed;
     }
 
-    void dispatchActivityResult(String who, int requestCode, 
+    void dispatchActivityResult(String who, int requestCode,
         int resultCode, Intent data) {
         if (false) Log.v(
             TAG, "Dispatching result: who=" + who + ", reqCode=" + requestCode
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 582ce3c..3f97c40 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -16,16 +16,21 @@
 
 package android.app;
 
+import android.animation.Animator;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
-import android.text.TextUtils;
+import android.transition.Transition;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.View;
 
+import java.util.ArrayList;
+import java.util.Map;
+
 /**
  * Helper class for building an options Bundle that can be used with
  * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
@@ -95,34 +100,30 @@
     public static final String KEY_ANIM_START_LISTENER = "android:animStartListener";
 
     /**
-     * A string array of names for the destination scene. This defines an API in the same
-     * way that intent action or extra names do and should follow a similar convention:
-     * "com.example.scene.FOO"
-     *
-     * @hide
-     */
-    public static final String KEY_DEST_SCENE_NAMES = "android:destSceneNames";
-
-    /**
-     * A string indicating the destination scene name that was chosen by the target.
-     * Used by {@link OnSceneTransitionStartedListener}.
-     * @hide
-     */
-    public static final String KEY_DEST_SCENE_NAME_CHOSEN = "android:destSceneNameChosen";
-
-    /**
-     * Callback for when scene transition is started.
-     * @hide
-     */
-    public static final String KEY_SCENE_TRANSITION_START_LISTENER =
-            "android:sceneTransitionStartListener";
-
-    /**
      * Arguments for the scene transition about to begin.
      * @hide
      */
     public static final String KEY_SCENE_TRANSITION_ARGS = "android:sceneTransitionArgs";
 
+    /**
+     * For Activity transitions, the calling Activity's TransitionListener used to
+     * notify the called Activity when the shared element and the exit transitions
+     * complete.
+     */
+    private static final String KEY_TRANSITION_COMPLETE_LISTENER
+            = "android:transitionCompleteListener";
+
+    /**
+     * For Activity transitions, the called Activity's listener to receive calls
+     * when transitions complete.
+     */
+    private static final String KEY_TRANSITION_TARGET_LISTENER = "android:transitionTargetListener";
+
+    /**
+     * The shared element's texture ID (TODO: not used yet).
+     */
+    private static final String KEY_SHARED_ELEMENT_TEXTURE_ID = "android:sharedElementTextureId";
+
     /** @hide */
     public static final int ANIM_NONE = 0;
     /** @hide */
@@ -145,10 +146,9 @@
     private int mStartY;
     private int mStartWidth;
     private int mStartHeight;
-    private String[] mDestSceneNames;
     private Bundle mTransitionArgs;
     private IRemoteCallback mAnimationStartedListener;
-    private IRemoteCallback mSceneTransitionStartedListener;
+    private IRemoteCallback mTransitionCompleteListener;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -215,24 +215,6 @@
         }
     }
 
-    private void setOnSceneTransitionStartedListener(Handler handler,
-            OnSceneTransitionStartedListener listener) {
-        if (listener != null) {
-            final Handler h = handler;
-            final OnSceneTransitionStartedListener l = listener;
-            mSceneTransitionStartedListener = new IRemoteCallback.Stub() {
-                @Override public void sendResult(final Bundle data) throws RemoteException {
-                    h.post(new Runnable() {
-                        public void run() {
-                            l.onSceneTransitionStarted(data != null ?
-                                    data.getString(KEY_DEST_SCENE_NAME_CHOSEN) : null);
-                        }
-                    });
-                }
-            };
-        }
-    }
-
     /**
      * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
      * to find out when the given animation has started running.
@@ -242,13 +224,10 @@
         void onAnimationStarted();
     }
 
-    /**
-     * Callback for use with {@link ActivityOptions#makeSceneTransitionAnimation}
-     * to find out when a transition is about to begin.
-     * @hide
-     */
-    public interface OnSceneTransitionStartedListener {
-        void onSceneTransitionStarted(String destSceneName);
+    /** @hide */
+    public interface ActivityTransitionTarget {
+        void sharedElementTransitionComplete();
+        void exitTransitionComplete();
     }
 
     /**
@@ -369,18 +348,35 @@
     }
 
     /**
-     * Create an ActivityOptions specifying an animation where an activity window is asked
-     * to perform animations within the window content.
+     * Create an ActivityOptions to transition between Activities using cross-Activity animation.
+     * When visual elements are to carry between Activities, args should be used to tell the called
+     * Activity about the location and size.
      *
-     * @hide
+     * TODO: Provide facility to capture layout and bitmap of shared elements.
+     *
+     * <p>When
+     * {@link android.app.Activity#startActivities(android.content.Intent[], android.os.Bundle)}
+     * is used with the {@link #toBundle()} result, the Activity's content scene will automatically
+     * transition out by setting their visibility to {@link View#INVISIBLE}. Shared elements
+     * ({@link android.view.View#setSharedElementName(String)}) are unmodified during the
+     * transition to allow the started Activity to seamlessly take it over. ViewGroups typically
+     * don't transition out, and instead transition out their children unless they have a
+     * background. To modify this behavior, use
+     * {@link android.view.ViewGroup#setTransitionGroup(boolean)}.</p>
+     *
+     * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
+     * enabled on the calling Activity to cause an exit transition. The same must be in
+     * the called Activity to get an entering transition.</p>
+     *
+     * @param args Contains information for transferring a view between this Activity and the
+     *             target Activity. Will be used by the called Activity to transition the
+     *             view to its eventual destination
+     * @see android.app.Activity#startSharedElementTransition(android.os.Bundle)
      */
-    public static ActivityOptions makeSceneTransitionAnimation(String[] destSceneNames,
-            Bundle args, OnSceneTransitionStartedListener listener, Handler handler) {
+    public static ActivityOptions makeSceneTransitionAnimation(Bundle args) {
         ActivityOptions opts = new ActivityOptions();
         opts.mAnimationType = ANIM_SCENE_TRANSITION;
-        opts.mDestSceneNames = destSceneNames;
         opts.mTransitionArgs = args;
-        opts.setOnSceneTransitionStartedListener(handler, listener);
         return opts;
     }
 
@@ -416,10 +412,9 @@
                 break;
 
             case ANIM_SCENE_TRANSITION:
-                mDestSceneNames = opts.getStringArray(KEY_DEST_SCENE_NAMES);
                 mTransitionArgs = opts.getBundle(KEY_SCENE_TRANSITION_ARGS);
-                mSceneTransitionStartedListener = IRemoteCallback.Stub.asInterface(
-                        opts.getBinder(KEY_SCENE_TRANSITION_START_LISTENER));
+                mTransitionCompleteListener = IRemoteCallback.Stub.asInterface(
+                        opts.getBinder(KEY_TRANSITION_COMPLETE_LISTENER));
                 break;
         }
     }
@@ -470,11 +465,6 @@
     }
 
     /** @hide */
-    public String[] getDestSceneNames() {
-        return mDestSceneNames;
-    }
-
-    /** @hide */
     public Bundle getSceneTransitionArgs() {
         return mTransitionArgs;
     }
@@ -485,19 +475,33 @@
     }
 
     /** @hide */
-    public void dispatchSceneTransitionStarted(String destScene) {
-        if (mSceneTransitionStartedListener != null) {
-            Bundle data = null;
-            if (!TextUtils.isEmpty(destScene)) {
-                data = new Bundle();
-                data.putString(KEY_DEST_SCENE_NAME_CHOSEN, destScene);
-            }
+    public void dispatchSceneTransitionStarted(final ActivityTransitionTarget target) {
+        boolean listenerSent = false;
+        if (mTransitionCompleteListener != null) {
+            IRemoteCallback callback = new IRemoteCallback.Stub() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    if (data == null) {
+                        target.exitTransitionComplete();
+                    } else {
+                        // TODO: Use texture id
+                        target.sharedElementTransitionComplete();
+                    }
+                }
+            };
+            Bundle bundle = new Bundle();
+            bundle.putBinder(KEY_TRANSITION_TARGET_LISTENER, callback.asBinder());
             try {
-                mSceneTransitionStartedListener.sendResult(data);
+                mTransitionCompleteListener.sendResult(bundle);
+                listenerSent = true;
             } catch (RemoteException e) {
-                Log.e(TAG, "Caught exception dispatching scene transition start", e);
+                Log.w(TAG, "Couldn't retrieve transition notifications", e);
             }
         }
+        if (!listenerSent) {
+            target.sharedElementTransitionComplete();
+            target.exitTransitionComplete();
+        }
     }
 
     /** @hide */
@@ -508,12 +512,6 @@
             } catch (RemoteException e) {
             }
         }
-        if (mSceneTransitionStartedListener != null) {
-            try {
-                mSceneTransitionStartedListener.sendResult(null);
-            } catch (RemoteException e) {
-            }
-        }
     }
 
     /** @hide */
@@ -545,9 +543,8 @@
                     }
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
-                mSceneTransitionStartedListener = null;
+                mTransitionCompleteListener = null;
                 mTransitionArgs = null;
-                mDestSceneNames = null;
                 break;
             case ANIM_SCALE_UP:
                 mAnimationType = otherOptions.mAnimationType;
@@ -562,9 +559,8 @@
                     }
                 }
                 mAnimationStartedListener = null;
-                mSceneTransitionStartedListener = null;
+                mTransitionCompleteListener = null;
                 mTransitionArgs = null;
-                mDestSceneNames = null;
                 break;
             case ANIM_THUMBNAIL_SCALE_UP:
             case ANIM_THUMBNAIL_SCALE_DOWN:
@@ -579,20 +575,12 @@
                     }
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
-                mSceneTransitionStartedListener = null;
+                mTransitionCompleteListener = null;
                 mTransitionArgs = null;
-                mDestSceneNames = null;
                 break;
             case ANIM_SCENE_TRANSITION:
                 mAnimationType = otherOptions.mAnimationType;
-                if (mSceneTransitionStartedListener != null) {
-                    try {
-                        mSceneTransitionStartedListener.sendResult(null);
-                    } catch (RemoteException e) {
-                    }
-                }
-                mSceneTransitionStartedListener = otherOptions.mSceneTransitionStartedListener;
-                mDestSceneNames = otherOptions.mDestSceneNames;
+                mTransitionCompleteListener = otherOptions.mTransitionCompleteListener;
                 mTransitionArgs = otherOptions.mTransitionArgs;
                 mThumbnail = null;
                 mAnimationStartedListener = null;
@@ -639,10 +627,11 @@
                 break;
             case ANIM_SCENE_TRANSITION:
                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
-                b.putStringArray(KEY_DEST_SCENE_NAMES, mDestSceneNames);
                 b.putBundle(KEY_SCENE_TRANSITION_ARGS, mTransitionArgs);
-                b.putBinder(KEY_SCENE_TRANSITION_START_LISTENER, mSceneTransitionStartedListener
-                        != null ? mSceneTransitionStartedListener.asBinder() : null);
+                if (mTransitionCompleteListener != null) {
+                    b.putBinder(KEY_TRANSITION_COMPLETE_LISTENER,
+                            mTransitionCompleteListener.asBinder());
+                }
                 break;
         }
         return b;
@@ -661,4 +650,123 @@
 
         return null;
     }
+
+    /** @hide */
+    public interface SharedElementSource {
+        int getTextureId();
+    }
+
+    /**
+     * In the calling Activity when transitioning out, sets the Transition to listen for
+     * changes.
+     * @hide
+     */
+    public void setExitTransition(Transition transition, SharedElementSource sharedElementSource) {
+        mTransitionCompleteListener = new ExitTransitionListener(transition, sharedElementSource);
+    }
+
+    private static class ExitTransitionListener extends IRemoteCallback.Stub
+            implements Transition.TransitionListener, Animator.AnimatorListener {
+        private ArrayList<Animator> mSharedElementAnimators = new ArrayList<Animator>();
+        private boolean mSharedElementNotified;
+        private Transition mExitTransition;
+        private IRemoteCallback mTransitionCompleteCallback;
+        private boolean mExitComplete;
+        private SharedElementSource mSharedElementSource;
+
+        public ExitTransitionListener(Transition transition, SharedElementSource sharedElementSource) {
+            mSharedElementSource = sharedElementSource;
+            mExitTransition = transition;
+            mExitTransition.addListener(this);
+        }
+
+        @Override
+        public void sendResult(Bundle data) throws RemoteException {
+            if (data != null) {
+                mTransitionCompleteCallback = IRemoteCallback.Stub.asInterface(
+                        data.getBinder(KEY_TRANSITION_TARGET_LISTENER));
+                notifySharedElement();
+                notifyExit();
+            }
+        }
+
+        @Override
+        public void onTransitionStart(Transition transition) {
+            ArrayMap<Animator, Transition.AnimationInfo> runningAnimators
+                    = Transition.getRunningAnimators();
+            for (Map.Entry<Animator, Transition.AnimationInfo> entry : runningAnimators.entrySet()) {
+                if (entry.getValue().view.getSharedElementName() != null) {
+                    mSharedElementAnimators.add(entry.getKey());
+                    entry.getKey().addListener(this);
+                }
+            }
+            notifySharedElement();
+        }
+
+        @Override
+        public void onTransitionEnd(Transition transition) {
+            mExitComplete = true;
+            notifyExit();
+            mExitTransition.removeListener(this);
+        }
+
+        @Override
+        public void onTransitionCancel(Transition transition) {
+            mExitComplete = true;
+            notifyExit();
+            mExitTransition.removeListener(this);
+        }
+
+        @Override
+        public void onTransitionPause(Transition transition) {
+        }
+
+        @Override
+        public void onTransitionResume(Transition transition) {
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mSharedElementAnimators.remove(animation);
+            notifySharedElement();
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mSharedElementAnimators.remove(animation);
+            notifySharedElement();
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+
+        private void notifySharedElement() {
+            if (!mSharedElementNotified && mSharedElementAnimators.isEmpty()
+                    && mTransitionCompleteCallback != null) {
+                mSharedElementNotified = true;
+                try {
+                    Bundle bundle = new Bundle();
+                    bundle.putInt(KEY_SHARED_ELEMENT_TEXTURE_ID, mSharedElementSource.getTextureId());
+                    mTransitionCompleteCallback.sendResult(bundle);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Couldn't notify that the transition ended", e);
+                }
+            }
+        }
+
+        private void notifyExit() {
+            if (mExitComplete && mTransitionCompleteCallback != null) {
+                try {
+                    mTransitionCompleteCallback.sendResult(null);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Couldn't notify that the transition ended", e);
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 25cde8c..df4ec78 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.graphics.SurfaceTexture;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -28,6 +29,7 @@
 import android.view.Surface;
 import android.view.TextureView;
 import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 
@@ -37,7 +39,6 @@
     private final TextureView mTextureView;
     private IActivityContainer mActivityContainer;
     private Activity mActivity;
-    private boolean mAttached;
     private int mWidth;
     private int mHeight;
     private Surface mSurface;
@@ -85,24 +86,33 @@
                     + e);
         }
 
-        final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
-        if (surfaceTexture != null) {
-            attachToSurface(surfaceTexture);
-        }
+        attachToSurfaceWhenReady();
     }
 
     @Override
     protected void onDetachedFromWindow() {
-        detachFromSurface();
+        if (mActivityContainer != null) {
+            detach();
+            mActivityContainer = null;
+        }
     }
 
     @Override
-    public boolean isAttachedToWindow() {
-        return mAttached;
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        if (visibility == View.VISIBLE) {
+            attachToSurfaceWhenReady();
+        } else {
+            detach();
+        }
+    }
+
+    public boolean isAttachedToDisplay() {
+        return mSurface != null;
     }
 
     public void startActivity(Intent intent) {
-        if (mActivityContainer != null && mAttached) {
+        if (mSurface != null) {
             try {
                 mActivityContainer.startActivity(intent);
             } catch (RemoteException e) {
@@ -111,40 +121,59 @@
         }
     }
 
-    /** Call when both mActivityContainer and mTextureView's SurfaceTexture are not null */
-    private void attachToSurface(SurfaceTexture surfaceTexture) {
+    public void startActivity(IntentSender intentSender) {
+        if (mSurface != null) {
+            try {
+                mActivityContainer.startActivityIntentSender(intentSender.getTarget());
+            } catch (RemoteException e) {
+                throw new IllegalStateException(
+                        "ActivityView: Unable to startActivity from IntentSender. " + e);
+            }
+        }
+    }
+
+    public void startActivity(PendingIntent pendingIntent) {
+        if (mSurface != null) {
+            try {
+                mActivityContainer.startActivityIntentSender(pendingIntent.getTarget());
+            } catch (RemoteException e) {
+                throw new IllegalStateException(
+                        "ActivityView: Unable to startActivity from PendingIntent. " + e);
+            }
+        }
+    }
+
+    private void attachToSurfaceWhenReady() {
+        final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
+        if (mActivityContainer == null || surfaceTexture == null || mSurface != null) {
+            // Either not ready to attach, or already attached.
+            return;
+        }
+
         WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
         DisplayMetrics metrics = new DisplayMetrics();
         wm.getDefaultDisplay().getMetrics(metrics);
 
         mSurface = new Surface(surfaceTexture);
         try {
-            mActivityContainer.attachToSurface(mSurface, mWidth, mHeight,
-                    metrics.densityDpi);
+            mActivityContainer.attachToSurface(mSurface, mWidth, mHeight, metrics.densityDpi);
         } catch (RemoteException e) {
-            mActivityContainer = null;
             mSurface.release();
             mSurface = null;
-            mAttached = false;
             throw new IllegalStateException(
                     "ActivityView: Unable to create ActivityContainer. " + e);
         }
-        mAttached = true;
     }
 
-    private void detachFromSurface() {
-        if (mActivityContainer != null) {
+    private void detach() {
+        if (mSurface != null) {
             try {
                 mActivityContainer.detachFromDisplay();
             } catch (RemoteException e) {
             }
-            mActivityContainer = null;
-        }
-        if (mSurface != null) {
             mSurface.release();
             mSurface = null;
         }
-        mAttached = false;
     }
 
     private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
@@ -154,7 +183,7 @@
             mWidth = width;
             mHeight = height;
             if (mActivityContainer != null) {
-                attachToSurface(surfaceTexture);
+                attachToSurfaceWhenReady();
             }
         }
 
@@ -167,7 +196,7 @@
         @Override
         public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
             Log.d(TAG, "onSurfaceTextureDestroyed");
-            detachFromSurface();
+            detach();
             return true;
         }
 
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index df1cf91..abd296a 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -18,6 +18,7 @@
 
 import android.app.IActivityContainerCallback;
 import android.content.Intent;
+import android.content.IIntentSender;
 import android.os.IBinder;
 import android.view.Surface;
 
@@ -27,5 +28,6 @@
     void attachToSurface(in Surface surface, int width, int height, int density);
     void detachFromDisplay();
     int startActivity(in Intent intent);
+    int startActivityIntentSender(in IIntentSender intentSender);
     int getDisplayId();
 }
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index d04e9db..af1810b 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -188,8 +188,7 @@
                 mSearchView.findViewById(com.android.internal.R.id.search_src_text);
         mAppIcon = (ImageView) findViewById(com.android.internal.R.id.search_app_icon);
         mSearchPlate = mSearchView.findViewById(com.android.internal.R.id.search_plate);
-        mWorkingSpinner = getContext().getResources().
-                getDrawable(com.android.internal.R.drawable.search_spinner);
+        mWorkingSpinner = getContext().getDrawable(com.android.internal.R.drawable.search_spinner);
         // TODO: Restore the spinner for slow suggestion lookups
         // mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
         //        null, null, mWorkingSpinner, null);
@@ -458,7 +457,7 @@
 
         // optionally show one or the other.
         if (mSearchable.useBadgeIcon()) {
-            icon = mActivityContext.getResources().getDrawable(mSearchable.getIconId());
+            icon = mActivityContext.getDrawable(mSearchable.getIconId());
             visibility = View.VISIBLE;
             if (DBG) Log.d(LOG_TAG, "Using badge icon: " + mSearchable.getIconId());
         } else if (mSearchable.useBadgeLabel()) {
diff --git a/core/java/android/app/maintenance/IIdleCallback.aidl b/core/java/android/app/maintenance/IIdleCallback.aidl
new file mode 100644
index 0000000..582dede
--- /dev/null
+++ b/core/java/android/app/maintenance/IIdleCallback.aidl
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2014, 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.app.maintenance;
+
+import android.app.maintenance.IIdleService;
+
+/**
+ * The server side of the idle maintenance IPC protocols.  The app-side implementation
+ * invokes on this interface to indicate completion of the (asynchronous) instructions
+ * issued by the server.
+ *
+ * In all cases, the 'who' parameter is the caller's service binder, used to track
+ * which idle service instance is reporting.
+ *
+ * {@hide}
+ */
+interface IIdleCallback {
+    /**
+     * Acknowledge receipt and processing of the asynchronous "start idle work" incall.
+     * 'result' is true if the app wants some time to perform ongoing background
+     * idle-time work; or false if the app declares that it does not need any time
+     * for such work.
+     */
+    void acknowledgeStart(int token, boolean result);
+
+    /**
+     * Acknowledge receipt and processing of the asynchronous "stop idle work" incall.
+     */
+    void acknowledgeStop(int token);
+
+    /*
+     * Tell the idle service manager that we're done with our idle maintenance, so that
+     * it can go on to the next one and stop attributing wakelock time to us etc.
+     *
+     * @param opToken The identifier passed in the startIdleMaintenance() call that
+     *        indicated the beginning of this service's idle timeslice.
+     */
+    void idleFinished(int token);
+}
diff --git a/core/java/android/app/maintenance/IIdleService.aidl b/core/java/android/app/maintenance/IIdleService.aidl
new file mode 100644
index 0000000..54abccd
--- /dev/null
+++ b/core/java/android/app/maintenance/IIdleService.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2014, 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.app.maintenance;
+
+import android.app.maintenance.IIdleCallback;
+
+/**
+ * Interface that the framework uses to communicate with application code
+ * that implements an idle-time "maintenance" service.  End user code does
+ * not implement this interface directly; instead, the app's idle service
+ * implementation will extend android.app.maintenance.IdleService.
+ * {@hide}
+ */
+oneway interface IIdleService {
+    /**
+     * Begin your idle-time work.
+     */
+    void startIdleMaintenance(IIdleCallback callbackBinder, int token);
+    void stopIdleMaintenance(IIdleCallback callbackBinder, int token);
+}
diff --git a/core/java/android/app/maintenance/IdleService.java b/core/java/android/app/maintenance/IdleService.java
new file mode 100644
index 0000000..2331b81
--- /dev/null
+++ b/core/java/android/app/maintenance/IdleService.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2014 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.app.maintenance;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+/**
+ * Idle maintenance API.  Full docs TBW (to be written).
+ */
+public abstract class IdleService extends Service {
+    private static final String TAG = "IdleService";
+
+    static final int MSG_START = 1;
+    static final int MSG_STOP = 2;
+    static final int MSG_FINISH = 3;
+
+    IdleHandler mHandler;
+    IIdleCallback mCallbackBinder;
+    int mToken;
+    final Object mHandlerLock = new Object();
+
+    void ensureHandler() {
+        synchronized (mHandlerLock) {
+            if (mHandler == null) {
+                mHandler = new IdleHandler(getMainLooper());
+            }
+        }
+    }
+
+    /**
+     * TBW: the idle service should supply an intent-filter handling this intent
+     * <p>
+     * <p class="note">The application must also protect the idle service with the
+     * {@code "android.permission.BIND_IDLE_SERVICE"} permission to ensure that other
+     * applications cannot maliciously bind to it.  If an idle service's manifest
+     * declaration does not require that permission, it will never be invoked.
+     * </p>
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.service.idle.IdleService";
+
+    /**
+     * Idle services must be protected with this permission:
+     *
+     * <pre class="prettyprint">
+     *     <service android:name="MyIdleService"
+     *              android:permission="android.permission.BIND_IDLE_SERVICE" >
+     *         ...
+     *     </service>
+     * </pre>
+     *
+     * <p>If an idle service is declared in the manifest but not protected with this
+     * permission, that service will be ignored by the OS.
+     */
+    public static final String PERMISSION_BIND =
+            "android.permission.BIND_IDLE_SERVICE";
+
+    // Trampoline: the callbacks are always run on the main thread
+    IIdleService mBinder = new IIdleService.Stub() {
+        @Override
+        public void startIdleMaintenance(IIdleCallback callbackBinder, int token)
+                throws RemoteException {
+            ensureHandler();
+            Message msg = mHandler.obtainMessage(MSG_START, token, 0, callbackBinder);
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void stopIdleMaintenance(IIdleCallback callbackBinder, int token)
+                throws RemoteException {
+            ensureHandler();
+            Message msg = mHandler.obtainMessage(MSG_STOP, token, 0, callbackBinder);
+            mHandler.sendMessage(msg);
+        }
+    };
+
+    /**
+     * Your application may begin doing "idle" maintenance work in the background.
+     * <p>
+     * Your application may continue to run in the background until it receives a call
+     * to {@link #onIdleStop()}, at which point you <i>must</i> cease doing work.  The
+     * OS will hold a wakelock on your application's behalf from the time this method is
+     * called until after the following call to {@link #onIdleStop()} returns.
+     * </p>
+     * <p>
+     * Returning {@code false} from this method indicates that you have no ongoing work
+     * to do at present.  The OS will respond by immediately calling {@link #onIdleStop()}
+     * and returning your application to its normal stopped state.  Returning {@code true}
+     * indicates that the application is indeed performing ongoing work, so the OS will
+     * let your application run in this state until it's no longer appropriate.
+     * </p>
+     * <p>
+     * You will always receive a matching call to {@link #onIdleStop()} even if your
+     * application returns {@code false} from this method.
+     *
+     * @return {@code true} to indicate that the application wishes to perform some ongoing
+     *     background work; {@code false} to indicate that it does not need to perform such
+     *     work at present.
+     */
+    public abstract boolean onIdleStart();
+
+    /**
+     * Your app's maintenance opportunity is over.  Once the application returns from
+     * this method, the wakelock held by the OS on its behalf will be released.
+     */
+    public abstract void onIdleStop();
+
+    /**
+     * Tell the OS that you have finished your idle work.  Calling this more than once,
+     * or calling it when you have not received an {@link #onIdleStart()} callback, is
+     * an error.
+     *
+     * <p>It is safe to call {@link #finishIdle()} from any thread.
+     */
+    public final void finishIdle() {
+        ensureHandler();
+        mHandler.sendEmptyMessage(MSG_FINISH);
+    }
+
+    class IdleHandler extends Handler {
+        IdleHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_START: {
+                    // Call the concrete onIdleStart(), reporting its return value back to
+                    // the OS.  If onIdleStart() throws, report it as a 'false' return but
+                    // rethrow the exception at the offending app.
+                    boolean result = false;
+                    IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
+                    mCallbackBinder = callbackBinder;
+                    final int token = mToken = msg.arg1;
+                    try {
+                        result = IdleService.this.onIdleStart();
+                    } catch (Exception e) {
+                        Log.e(TAG, "Unable to start idle workload", e);
+                        throw new RuntimeException(e);
+                    } finally {
+                        // don't bother if the service already called finishIdle()
+                        if (mCallbackBinder != null) {
+                            try {
+                                callbackBinder.acknowledgeStart(token, result);
+                            } catch (RemoteException re) {
+                                Log.e(TAG, "System unreachable to start idle workload");
+                            }
+                        }
+                    }
+                    break;
+                }
+
+                case MSG_STOP: {
+                    // Structured just like MSG_START for the stop-idle bookend call.
+                    IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
+                    final int token = msg.arg1;
+                    try {
+                        IdleService.this.onIdleStop();
+                    } catch (Exception e) {
+                        Log.e(TAG, "Unable to stop idle workload", e);
+                        throw new RuntimeException(e);
+                    } finally {
+                        if (mCallbackBinder != null) {
+                            try {
+                                callbackBinder.acknowledgeStop(token);
+                            } catch (RemoteException re) {
+                                Log.e(TAG, "System unreachable to stop idle workload");
+                            }
+                        }
+                    }
+                    break;
+                }
+
+                case MSG_FINISH: {
+                    if (mCallbackBinder != null) {
+                        try {
+                            mCallbackBinder.idleFinished(mToken);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "System unreachable to finish idling");
+                        } finally {
+                            mCallbackBinder = null;
+                        }
+                    } else {
+                        Log.e(TAG, "finishIdle() called but the idle service is not started");
+                    }
+                    break;
+                }
+
+                default: {
+                    Slog.w(TAG, "Unknown message " + msg.what);
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mBinder.asBinder();
+    }
+
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ac08d9b..9f90de0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -376,6 +376,19 @@
         return getResources().getString(resId, formatArgs);
     }
 
+    /**
+     * Return a drawable object associated with a particular resource ID and
+     * styled for the current theme.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @return Drawable An object that can be used to draw this resource.
+     */
+    public final Drawable getDrawable(int id) {
+        return getResources().getDrawable(id, getTheme());
+    }
+
      /**
      * Set the base theme for this context.  Note that this should be called
      * before any views are instantiated in the Context (for example before
diff --git a/core/java/android/content/SyncActivityTooManyDeletes.java b/core/java/android/content/SyncActivityTooManyDeletes.java
index 350f35e..093fb08 100644
--- a/core/java/android/content/SyncActivityTooManyDeletes.java
+++ b/core/java/android/content/SyncActivityTooManyDeletes.java
@@ -95,7 +95,7 @@
 //                try {
 //                    final Context authContext = createPackageContext(desc.packageName, 0);
 //                    ImageView imageView = new ImageView(this);
-//                    imageView.setImageDrawable(authContext.getResources().getDrawable(desc.iconId));
+//                    imageView.setImageDrawable(authContext.getDrawable(desc.iconId));
 //                    ll.addView(imageView, lp);
 //                } catch (PackageManager.NameNotFoundException e) {
 //                }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index b0b8d2d..aa96f0e 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -94,12 +94,13 @@
     private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists
             = new LongSparseArray<ColorStateList>();
 
-    private static Resources mSystem = null;
+    // Used by BridgeResources in layoutlib
+    static Resources mSystem = null;
+
     private static boolean sPreloaded;
     private static int sPreloadedDensity;
 
     // These are protected by mAccessLock.
-
     private final Object mAccessLock = new Object();
     private final Configuration mTmpConfig = new Configuration();
     private final LongSparseArray<WeakReference<Drawable.ConstantState>> mDrawableCache
@@ -685,12 +686,27 @@
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
-     *
-     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
-     * 
      * @return Drawable An object that can be used to draw this resource.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
      */
     public Drawable getDrawable(int id) throws NotFoundException {
+        return getDrawable(id, null);
+    }
+
+    /**
+     * Return a drawable object associated with a particular resource ID and
+     * styled for the specified theme.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @param theme The theme used to style the drawable attributes.
+     * @return Drawable An object that can be used to draw this resource.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     */
+    public Drawable getDrawable(int id, Theme theme) throws NotFoundException {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
@@ -701,7 +717,7 @@
             }
             getValue(id, value, true);
         }
-        Drawable res = loadDrawable(value, id);
+        final Drawable res = loadDrawable(value, id, theme);
         synchronized (mAccessLock) {
             if (mTmpValue == null) {
                 mTmpValue = value;
@@ -719,17 +735,36 @@
      * depending on the underlying resource -- for example, a solid color, PNG
      * image, scalable image, etc. The Drawable API hides these implementation
      * details.
-     * 
+     *
      * @param id The desired resource identifier, as generated by the aapt tool.
      *            This integer encodes the package, type, and resource entry.
      *            The value 0 is an invalid identifier.
      * @param density the desired screen density indicated by the resource as
      *            found in {@link DisplayMetrics}.
+     * @return Drawable An object that can be used to draw this resource.
      * @throws NotFoundException Throws NotFoundException if the given ID does
      *             not exist.
-     * @return Drawable An object that can be used to draw this resource.
+     * @see #getDrawableForDensity(int, int, Theme)
      */
     public Drawable getDrawableForDensity(int id, int density) throws NotFoundException {
+        return getDrawableForDensity(id, density, null);
+    }
+
+    /**
+     * Return a drawable object associated with a particular resource ID for the
+     * given screen density in DPI and styled for the specified theme.
+     *
+     * @param id The desired resource identifier, as generated by the aapt tool.
+     *            This integer encodes the package, type, and resource entry.
+     *            The value 0 is an invalid identifier.
+     * @param density The desired screen density indicated by the resource as
+     *            found in {@link DisplayMetrics}.
+     * @param theme The theme used to style the drawable attributes.
+     * @return Drawable An object that can be used to draw this resource.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *             not exist.
+     */
+    public Drawable getDrawableForDensity(int id, int density, Theme theme) {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
@@ -756,7 +791,7 @@
             }
         }
 
-        Drawable res = loadDrawable(value, id);
+        final Drawable res = loadDrawable(value, id, theme);
         synchronized (mAccessLock) {
             if (mTmpValue == null) {
                 mTmpValue = value;
@@ -1250,8 +1285,9 @@
          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
          */
         public TypedArray obtainStyledAttributes(int[] attrs) {
-            int len = attrs.length;
-            TypedArray array = getCachedStyledAttributes(len);
+            final int len = attrs.length;
+            final TypedArray array = getCachedStyledAttributes(len);
+            array.mTheme = this;
             array.mRsrcs = attrs;
             AssetManager.applyStyle(mTheme, 0, 0, 0, attrs,
                     array.mData, array.mIndices);
@@ -1278,10 +1314,10 @@
          * @see #obtainStyledAttributes(int[])
          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
          */
-        public TypedArray obtainStyledAttributes(int resid, int[] attrs)
-                throws NotFoundException {
-            int len = attrs.length;
-            TypedArray array = getCachedStyledAttributes(len);
+        public TypedArray obtainStyledAttributes(int resid, int[] attrs) throws NotFoundException {
+            final int len = attrs.length;
+            final TypedArray array = getCachedStyledAttributes(len);
+            array.mTheme = this;
             array.mRsrcs = attrs;
 
             AssetManager.applyStyle(mTheme, 0, resid, 0, attrs,
@@ -1365,19 +1401,18 @@
          */
         public TypedArray obtainStyledAttributes(AttributeSet set,
                 int[] attrs, int defStyleAttr, int defStyleRes) {
-            int len = attrs.length;
-            TypedArray array = getCachedStyledAttributes(len);
+            final int len = attrs.length;
+            final TypedArray array = getCachedStyledAttributes(len);
 
             // XXX note that for now we only work with compiled XML files.
             // To support generic XML files we will need to manually parse
             // out the attributes from the XML file (applying type information
             // contained in the resources and such).
-            XmlBlock.Parser parser = (XmlBlock.Parser)set;
-            AssetManager.applyStyle(
-                mTheme, defStyleAttr, defStyleRes,
-                parser != null ? parser.mParseState : 0, attrs,
-                        array.mData, array.mIndices);
+            final XmlBlock.Parser parser = (XmlBlock.Parser)set;
+            AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+                    parser != null ? parser.mParseState : 0, attrs, array.mData, array.mIndices);
 
+            array.mTheme = this;
             array.mRsrcs = attrs;
             array.mXml = parser;
 
@@ -1443,6 +1478,21 @@
         }
 
         /**
+         * Return a drawable object associated with a particular resource ID
+         * and styled for the Theme.
+         *
+         * @param id The desired resource identifier, as generated by the aapt
+         *           tool. This integer encodes the package, type, and resource
+         *           entry. The value 0 is an invalid identifier.
+         * @return Drawable An object that can be used to draw this resource.
+         * @throws NotFoundException Throws NotFoundException if the given ID
+         *         does not exist.
+         */
+        public Drawable getDrawable(int id) throws NotFoundException {
+            return Resources.this.getDrawable(id, this);
+        }
+
+        /**
          * Print contents of this theme out to the log.  For debugging only.
          * 
          * @param priority The log priority to use.
@@ -1452,7 +1502,8 @@
         public void dump(int priority, String tag, String prefix) {
             AssetManager.dumpTheme(mTheme, priority, tag, prefix);
         }
-        
+
+        @Override
         protected void finalize() throws Throwable {
             super.finalize();
             mAssets.releaseTheme(mTheme);
@@ -1463,6 +1514,7 @@
             mTheme = mAssets.createTheme();
         }
 
+        @SuppressWarnings("hiding")
         private final AssetManager mAssets;
         private final long mTheme;
     }
@@ -2027,14 +2079,14 @@
         return true;
     }
 
-    /*package*/ Drawable loadDrawable(TypedValue value, int id)
-            throws NotFoundException {
-
+    /*package*/ Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
         if (TRACE_FOR_PRELOAD) {
             // Log only framework resources
             if ((id >>> 24) == 0x1) {
                 final String name = getResourceName(id);
-                if (name != null) android.util.Log.d("PreloadDrawable", name);
+                if (name != null) {
+                    Log.d("PreloadDrawable", name);
+                }
             }
         }
 
@@ -2239,12 +2291,12 @@
                     "Resource is not a ColorStateList (color or path): " + value);
         }
         
-        String file = value.string.toString();
+        final String file = value.string.toString();
 
         if (file.endsWith(".xml")) {
             Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
             try {
-                XmlResourceParser rp = loadXmlResourceParser(
+                final XmlResourceParser rp = loadXmlResourceParser(
                         file, id, value.assetCookie, "colorstatelist"); 
                 csl = ColorStateList.createFromXml(this, rp);
                 rp.close();
@@ -2371,7 +2423,6 @@
         synchronized (mAccessLock) {
             final TypedArray cached = mCachedStyledAttributes;
             if (cached == null || cached.mData.length < attrs.mData.length) {
-                attrs.mXml = null;
                 mCachedStyledAttributes = attrs;
             }
         }
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 87d65a5..4858d08 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -45,7 +45,8 @@
     /*package*/ int[] mIndices;
     /*package*/ int mLength;
     /*package*/ TypedValue mValue = new TypedValue();
-   
+    /*package*/ Resources.Theme mTheme;
+
     /**
      * Return the number of values in this array.
      */
@@ -600,7 +601,7 @@
                                    + " cookie=" + value.assetCookie);
                 System.out.println("******************************************************************");
             }
-            return mResources.loadDrawable(value, value.resourceId);
+            return mResources.loadDrawable(value, value.resourceId, mTheme);
         }
         return null;
     }
@@ -690,6 +691,10 @@
      */
     public void recycle() {
         mResources.recycleCachedStyledAttributes(this);
+
+        mXml = null;
+        mRsrcs = null;
+        mTheme = null;
     }
 
     private boolean getValueAt(int index, TypedValue outValue) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 495bf51..bb8b184 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -255,20 +255,27 @@
             new Key<byte[]>("android.control.awbAvailableModes", byte[].class);
 
     /**
-     * <p>For AE, AWB, and AF, how many individual
-     * regions can be listed for metering?</p>
+     * <p>List of the maximum number of regions that can be used for metering in
+     * auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
+     * this corresponds to the the maximum number of elements in
+     * {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}, {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions},
+     * and {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_REGIONS
+     * @see CaptureRequest#CONTROL_AF_REGIONS
+     * @see CaptureRequest#CONTROL_AWB_REGIONS
      */
-    public static final Key<Integer> CONTROL_MAX_REGIONS =
-            new Key<Integer>("android.control.maxRegions", int.class);
+    public static final Key<int[]> CONTROL_MAX_REGIONS =
+            new Key<int[]>("android.control.maxRegions", int[].class);
 
     /**
-     * <p>Whether this camera has a
-     * flash</p>
+     * <p>Whether this camera device has a
+     * flash.</p>
      * <p>If no flash, none of the flash controls do
-     * anything. All other metadata should return 0</p>
+     * anything. All other metadata should return 0.</p>
      */
-    public static final Key<Byte> FLASH_INFO_AVAILABLE =
-            new Key<Byte>("android.flash.info.available", byte.class);
+    public static final Key<Boolean> FLASH_INFO_AVAILABLE =
+            new Key<Boolean>("android.flash.info.available", boolean.class);
 
     /**
      * <p>Supported resolutions for the JPEG thumbnail</p>
@@ -515,8 +522,9 @@
 
     /**
      * <p>Area of raw data which corresponds to only
-     * active pixels; smaller or equal to
-     * pixelArraySize.</p>
+     * active pixels.</p>
+     * <p>It is smaller or equal to
+     * sensor full pixel array, which could include the black calibration pixels.</p>
      */
     public static final Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE =
             new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class);
@@ -529,19 +537,29 @@
 
     /**
      * <p>Range of valid exposure
-     * times</p>
+     * times used by {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}.</p>
+     *
+     * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      */
     public static final Key<long[]> SENSOR_INFO_EXPOSURE_TIME_RANGE =
             new Key<long[]>("android.sensor.info.exposureTimeRange", long[].class);
 
     /**
      * <p>Maximum possible frame duration (minimum frame
-     * rate)</p>
-     * <p>Minimum duration is a function of resolution,
-     * processing settings. See
-     * android.scaler.availableProcessedMinDurations
-     * android.scaler.availableJpegMinDurations
-     * android.scaler.availableRawMinDurations</p>
+     * rate).</p>
+     * <p>The largest possible android.sensor.frameDuration
+     * that will be accepted by the camera device. Attempting to use
+     * frame durations beyond the maximum will result in the frame duration
+     * being clipped to the maximum. See that control
+     * for a full definition of frame durations.</p>
+     * <p>Refer to
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations},
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations}, and
+     * android.scaler.availableRawMinDurations for the minimum
+     * frame duration values.</p>
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS
+     * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
      */
     public static final Key<Long> SENSOR_INFO_MAX_FRAME_DURATION =
             new Key<Long>("android.sensor.info.maxFrameDuration", long.class);
@@ -569,11 +587,11 @@
 
     /**
      * <p>Maximum sensitivity that is implemented
-     * purely through analog gain</p>
+     * purely through analog gain.</p>
      * <p>For {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} values less than or
      * equal to this, all applied gain must be analog. For
-     * values above this, it can be a mix of analog and
-     * digital</p>
+     * values above this, the gain applied can be a mix of analog and
+     * digital.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index e839be3..a1f432d 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1372,22 +1372,28 @@
     public static final int FLASH_STATE_UNAVAILABLE = 0;
 
     /**
-     * <p>if android.flash.available is true Flash is
+     * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash is
      * charging and cannot be fired</p>
+     *
+     * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
      * @see CaptureResult#FLASH_STATE
      */
     public static final int FLASH_STATE_CHARGING = 1;
 
     /**
-     * <p>if android.flash.available is true Flash is
+     * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash is
      * ready to fire</p>
+     *
+     * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
      * @see CaptureResult#FLASH_STATE
      */
     public static final int FLASH_STATE_READY = 2;
 
     /**
-     * <p>if android.flash.available is true Flash fired
+     * <p>if {@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} is true Flash fired
      * for this capture</p>
+     *
+     * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
      * @see CaptureResult#FLASH_STATE
      */
     public static final int FLASH_STATE_FIRED = 3;
@@ -1397,11 +1403,21 @@
     //
 
     /**
+     * <p>The lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, android.lens.focusDistance
+     * android.lens.filterDensity and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) are not changing.</p>
+     *
+     * @see CaptureRequest#LENS_APERTURE
+     * @see CaptureRequest#LENS_FOCAL_LENGTH
      * @see CaptureResult#LENS_STATE
      */
     public static final int LENS_STATE_STATIONARY = 0;
 
     /**
+     * <p>Any of the lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, android.lens.focusDistance
+     * android.lens.filterDensity or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is changing.</p>
+     *
+     * @see CaptureRequest#LENS_APERTURE
+     * @see CaptureRequest#LENS_FOCAL_LENGTH
      * @see CaptureResult#LENS_STATE
      */
     public static final int LENS_STATE_MOVING = 1;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 56508e8..1327ba9 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -510,9 +510,9 @@
 
     /**
      * <p>List of areas to use for
-     * metering</p>
+     * metering.</p>
      * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
      * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
@@ -524,7 +524,7 @@
      * needs to be used by the HAL. If the metering region is
      * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
      * should ignore the sections outside the region and output the
-     * used sections in the frame metadata</p>
+     * used sections in the frame metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -582,9 +582,9 @@
 
     /**
      * <p>List of areas to use for focus
-     * estimation</p>
+     * estimation.</p>
      * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
      * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
@@ -596,7 +596,7 @@
      * needs to be used by the HAL. If the focusing region is
      * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
      * should ignore the sections outside the region and output the
-     * used sections in the frame metadata</p>
+     * used sections in the frame metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -668,10 +668,10 @@
 
     /**
      * <p>List of areas to use for illuminant
-     * estimation</p>
+     * estimation.</p>
      * <p>Only used in AUTO mode.</p>
      * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
      * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
@@ -683,7 +683,7 @@
      * needs to be used by the HAL. If the metering region is
      * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
      * should ignore the sections outside the region and output the
-     * used sections in the frame metadata</p>
+     * used sections in the frame metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -826,7 +826,7 @@
     /**
      * <p>The desired mode for for the camera device's flash control.</p>
      * <p>This control is only effective when flash unit is available
-     * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} != 0</code>).</p>
+     * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} == true</code>).</p>
      * <p>When this control is used, the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} must be set to ON or OFF.
      * Otherwise, the camera device auto-exposure related flash control (ON_AUTO_FLASH,
      * ON_ALWAYS_FLASH, or ON_AUTO_FLASH_REDEYE) will override this control.</p>
@@ -837,10 +837,12 @@
      * ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p>
      * <p>When set to TORCH, the flash will be on continuously. This mode can be used
      * for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
+     * <p>The flash status will be reported by {@link CaptureResult#FLASH_STATE android.flash.state} in the capture result metadata.</p>
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
      * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
+     * @see CaptureResult#FLASH_STATE
      * @see #FLASH_MODE_OFF
      * @see #FLASH_MODE_SINGLE
      * @see #FLASH_MODE_TORCH
@@ -913,7 +915,8 @@
      * to achieve manual exposure control.</p>
      * <p>The requested aperture value may take several frames to reach the
      * requested value; the camera device will report the current (intermediate)
-     * aperture size in capture result metadata while the aperture is changing.</p>
+     * aperture size in capture result metadata while the aperture is changing.
+     * While the aperture is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
      * <p>When this is supported and {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is one of
      * the ON modes, this will be overridden by the camera device
      * auto-exposure algorithm, the overridden values are then provided
@@ -921,6 +924,7 @@
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES
+     * @see CaptureResult#LENS_STATE
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      * @see CaptureRequest#SENSOR_SENSITIVITY
      */
@@ -940,8 +944,12 @@
      * in no reduction of the incoming light, and setting this to 2 would
      * mean that the filter is set to reduce incoming light by two stops
      * (allowing 1/4 of the prior amount of light to the sensor).</p>
+     * <p>It may take several frames before the lens filter density changes
+     * to the requested value. While the filter density is still changing,
+     * {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
      *
      * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES
+     * @see CaptureResult#LENS_STATE
      */
     public static final Key<Float> LENS_FILTER_DENSITY =
             new Key<Float>("android.lens.filterDensity", float.class);
@@ -953,7 +961,7 @@
      * view of the camera device, and is usually used for optical zoom.</p>
      * <p>Like {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}, this
      * setting won't be applied instantaneously, and it may take several
-     * frames before the lens can move to the requested focal length.
+     * frames before the lens can change to the requested focal length.
      * While the focal length is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will
      * be set to MOVING.</p>
      * <p>This is expected not to be supported on most devices.</p>
@@ -968,8 +976,16 @@
     /**
      * <p>Distance to plane of sharpest focus,
      * measured from frontmost surface of the lens</p>
-     * <p>0 = infinity focus. Used value should be clamped
-     * to (0,minimum focus distance)</p>
+     * <p>0 means infinity focus. Used value will be clamped
+     * to [0, {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}].</p>
+     * <p>Like {@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, this setting won't be applied
+     * instantaneously, and it may take several frames before the lens
+     * can move to the requested focus distance. While the lens is still moving,
+     * {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
+     *
+     * @see CaptureRequest#LENS_FOCAL_LENGTH
+     * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
+     * @see CaptureResult#LENS_STATE
      */
     public static final Key<Float> LENS_FOCUS_DISTANCE =
             new Key<Float>("android.lens.focusDistance", float.class);
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 0ded5bd..46d95b1 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -212,9 +212,9 @@
 
     /**
      * <p>List of areas to use for
-     * metering</p>
+     * metering.</p>
      * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
      * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
@@ -226,7 +226,7 @@
      * needs to be used by the HAL. If the metering region is
      * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
      * should ignore the sections outside the region and output the
-     * used sections in the frame metadata</p>
+     * used sections in the frame metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -405,9 +405,9 @@
 
     /**
      * <p>List of areas to use for focus
-     * estimation</p>
+     * estimation.</p>
      * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
      * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
@@ -419,7 +419,7 @@
      * needs to be used by the HAL. If the focusing region is
      * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
      * should ignore the sections outside the region and output the
-     * used sections in the frame metadata</p>
+     * used sections in the frame metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -794,10 +794,10 @@
 
     /**
      * <p>List of areas to use for illuminant
-     * estimation</p>
+     * estimation.</p>
      * <p>Only used in AUTO mode.</p>
      * <p>Each area is a rectangle plus weight: xmin, ymin,
-     * xmax, ymax, weight. The rectangle is defined inclusive of the
+     * xmax, ymax, weight. The rectangle is defined to be inclusive of the
      * specified coordinates.</p>
      * <p>The coordinate system is based on the active pixel array,
      * with (0,0) being the top-left pixel in the active pixel array, and
@@ -809,7 +809,7 @@
      * needs to be used by the HAL. If the metering region is
      * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
      * should ignore the sections outside the region and output the
-     * used sections in the frame metadata</p>
+     * used sections in the frame metadata.</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
@@ -965,7 +965,7 @@
     /**
      * <p>The desired mode for for the camera device's flash control.</p>
      * <p>This control is only effective when flash unit is available
-     * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} != 0</code>).</p>
+     * (<code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} == true</code>).</p>
      * <p>When this control is used, the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} must be set to ON or OFF.
      * Otherwise, the camera device auto-exposure related flash control (ON_AUTO_FLASH,
      * ON_ALWAYS_FLASH, or ON_AUTO_FLASH_REDEYE) will override this control.</p>
@@ -976,10 +976,12 @@
      * ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p>
      * <p>When set to TORCH, the flash will be on continuously. This mode can be used
      * for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
+     * <p>The flash status will be reported by {@link CaptureResult#FLASH_STATE android.flash.state} in the capture result metadata.</p>
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
      * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
+     * @see CaptureResult#FLASH_STATE
      * @see #FLASH_MODE_OFF
      * @see #FLASH_MODE_SINGLE
      * @see #FLASH_MODE_TORCH
@@ -989,7 +991,12 @@
 
     /**
      * <p>Current state of the flash
-     * unit</p>
+     * unit.</p>
+     * <p>When the camera device doesn't have flash unit
+     * (i.e. <code>{@link CameraCharacteristics#FLASH_INFO_AVAILABLE android.flash.info.available} == false</code>), this state will always be UNAVAILABLE.
+     * Other states indicate the current flash status.</p>
+     *
+     * @see CameraCharacteristics#FLASH_INFO_AVAILABLE
      * @see #FLASH_STATE_UNAVAILABLE
      * @see #FLASH_STATE_CHARGING
      * @see #FLASH_STATE_READY
@@ -1063,7 +1070,8 @@
      * to achieve manual exposure control.</p>
      * <p>The requested aperture value may take several frames to reach the
      * requested value; the camera device will report the current (intermediate)
-     * aperture size in capture result metadata while the aperture is changing.</p>
+     * aperture size in capture result metadata while the aperture is changing.
+     * While the aperture is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
      * <p>When this is supported and {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is one of
      * the ON modes, this will be overridden by the camera device
      * auto-exposure algorithm, the overridden values are then provided
@@ -1071,6 +1079,7 @@
      *
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES
+     * @see CaptureResult#LENS_STATE
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      * @see CaptureRequest#SENSOR_SENSITIVITY
      */
@@ -1090,8 +1099,12 @@
      * in no reduction of the incoming light, and setting this to 2 would
      * mean that the filter is set to reduce incoming light by two stops
      * (allowing 1/4 of the prior amount of light to the sensor).</p>
+     * <p>It may take several frames before the lens filter density changes
+     * to the requested value. While the filter density is still changing,
+     * {@link CaptureResult#LENS_STATE android.lens.state} will be set to MOVING.</p>
      *
      * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES
+     * @see CaptureResult#LENS_STATE
      */
     public static final Key<Float> LENS_FILTER_DENSITY =
             new Key<Float>("android.lens.filterDensity", float.class);
@@ -1103,7 +1116,7 @@
      * view of the camera device, and is usually used for optical zoom.</p>
      * <p>Like {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}, this
      * setting won't be applied instantaneously, and it may take several
-     * frames before the lens can move to the requested focal length.
+     * frames before the lens can change to the requested focal length.
      * While the focal length is still changing, {@link CaptureResult#LENS_STATE android.lens.state} will
      * be set to MOVING.</p>
      * <p>This is expected not to be supported on most devices.</p>
@@ -1148,7 +1161,35 @@
             new Key<Integer>("android.lens.opticalStabilizationMode", int.class);
 
     /**
-     * <p>Current lens status</p>
+     * <p>Current lens status.</p>
+     * <p>For lens parameters {@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+     * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} and {@link CaptureRequest#LENS_APERTURE android.lens.aperture}, when changes are requested,
+     * they may take several frames to reach the requested values. This state indicates
+     * the current status of the lens parameters.</p>
+     * <p>When the state is STATIONARY, the lens parameters are not changing. This could be
+     * either because the parameters are all fixed, or because the lens has had enough
+     * time to reach the most recently-requested values.
+     * If all these lens parameters are not changable for a camera device, as listed below:</p>
+     * <ul>
+     * <li>Fixed focus (<code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} == 0</code>), which means
+     * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} parameter will always be 0.</li>
+     * <li>Fixed focal length ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS android.lens.info.availableFocalLengths} contains single value),
+     * which means the optical zoom is not supported.</li>
+     * <li>No ND filter ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES android.lens.info.availableFilterDensities} contains only 0).</li>
+     * <li>Fixed aperture ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES android.lens.info.availableApertures} contains single value).</li>
+     * </ul>
+     * <p>Then this state will always be STATIONARY.</p>
+     * <p>When the state is MOVING, it indicates that at least one of the lens parameters
+     * is changing.</p>
+     *
+     * @see CaptureRequest#LENS_APERTURE
+     * @see CaptureRequest#LENS_FILTER_DENSITY
+     * @see CaptureRequest#LENS_FOCAL_LENGTH
+     * @see CaptureRequest#LENS_FOCUS_DISTANCE
+     * @see CameraCharacteristics#LENS_INFO_AVAILABLE_APERTURES
+     * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FILTER_DENSITIES
+     * @see CameraCharacteristics#LENS_INFO_AVAILABLE_FOCAL_LENGTHS
+     * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
      * @see #LENS_STATE_STATIONARY
      * @see #LENS_STATE_MOVING
      */
@@ -1593,10 +1634,24 @@
             new Key<Rational[]>("android.statistics.predictedColorTransform", Rational[].class);
 
     /**
-     * <p>The HAL estimated scene illumination lighting
-     * frequency</p>
-     * <p>Report NONE if there doesn't appear to be flickering
-     * illumination</p>
+     * <p>The camera device estimated scene illumination lighting
+     * frequency.</p>
+     * <p>Many light sources, such as most fluorescent lights, flicker at a rate
+     * that depends on the local utility power standards. This flicker must be
+     * accounted for by auto-exposure routines to avoid artifacts in captured images.
+     * The camera device uses this entry to tell the application what the scene
+     * illuminant frequency is.</p>
+     * <p>When manual exposure control is enabled
+     * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == OFF</code>),
+     * the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't do the antibanding, and the
+     * application can ensure it selects exposure times that do not cause banding
+     * issues by looking into this metadata field. See android.control.aeAntibandingMode
+     * for more details.</p>
+     * <p>Report NONE if there doesn't appear to be flickering illumination.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_MODE
      * @see #STATISTICS_SCENE_FLICKER_NONE
      * @see #STATISTICS_SCENE_FLICKER_50HZ
      * @see #STATISTICS_SCENE_FLICKER_60HZ
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6ac126e..3a35cb9 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -800,6 +800,8 @@
      * Ensure that a network route exists to deliver traffic to the specified
      * host via the specified network interface. An attempt to add a route that
      * already exists is ignored, but treated as successful.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * @param networkType the type of the network over which traffic to the specified
      * host is to be routed
      * @param hostAddress the IP address of the host to which the route is desired
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index d9c35c0..3c3d8ec 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -306,18 +306,18 @@
                     if (VDBG) {
                         Slog.d(TAG, "TelephonyMgr.DataConnectionStateChanged");
                         if (mNetworkInfo != null) {
-                            Slog.d(TAG, "NetworkInfo = " + mNetworkInfo.toString());
-                            Slog.d(TAG, "subType = " + String.valueOf(mNetworkInfo.getSubtype()));
+                            Slog.d(TAG, "NetworkInfo = " + mNetworkInfo);
+                            Slog.d(TAG, "subType = " + mNetworkInfo.getSubtype());
                             Slog.d(TAG, "subType = " + mNetworkInfo.getSubtypeName());
                         }
                         if (mLinkProperties != null) {
-                            Slog.d(TAG, "LinkProperties = " + mLinkProperties.toString());
+                            Slog.d(TAG, "LinkProperties = " + mLinkProperties);
                         } else {
                             Slog.d(TAG, "LinkProperties = " );
                         }
 
                         if (mLinkCapabilities != null) {
-                            Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities.toString());
+                            Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities);
                         } else {
                             Slog.d(TAG, "LinkCapabilities = " );
                         }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 2afea1f..27c0f5d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -452,6 +452,56 @@
         }
     }
 
+    public final static class HistoryTag {
+        public String string;
+        public int uid;
+
+        public int poolIdx;
+
+        public void setTo(HistoryTag o) {
+            string = o.string;
+            uid = o.uid;
+            poolIdx = o.poolIdx;
+        }
+
+        public void setTo(String _string, int _uid) {
+            string = _string;
+            uid = _uid;
+            poolIdx = -1;
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(string);
+            dest.writeInt(uid);
+        }
+
+        public void readFromParcel(Parcel src) {
+            string = src.readString();
+            uid = src.readInt();
+            poolIdx = -1;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            HistoryTag that = (HistoryTag) o;
+
+            if (uid != that.uid) return false;
+            if (!string.equals(that.string)) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = string.hashCode();
+            result = 31 * result + uid;
+            return result;
+        }
+    }
+
     public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
         
@@ -500,7 +550,7 @@
         public static final int STATE_PHONE_STATE_MASK = 0x7 << STATE_PHONE_STATE_SHIFT;
         // Constants from DATA_CONNECTION_*
         public static final int STATE_DATA_CONNECTION_SHIFT = 9;
-        public static final int STATE_DATA_CONNECTION_MASK = 0x1f;
+        public static final int STATE_DATA_CONNECTION_MASK = 0x1f << STATE_DATA_CONNECTION_SHIFT;
 
         // These states always appear directly in the first int token
         // of a delta change; they should be ones that change relatively
@@ -529,21 +579,30 @@
 
         public int states;
 
+        // The wake lock that was acquired at this point.
+        public HistoryTag wakelockTag;
+
         public static final int EVENT_NONE = 0;
         public static final int EVENT_PROC_STARTED = 1;
         public static final int EVENT_PROC_FINISHED = 2;
 
         // For CMD_EVENT.
         public int eventCode;
-        public String eventName;
-        public int eventNameIdx;    // only filled in when iterating.
-        public int eventUid;
+        public HistoryTag eventTag;
+
+        // Meta-data when reading.
+        public int numReadInts;
+
+        // Pre-allocated objects.
+        public final HistoryTag localWakelockTag = new HistoryTag();
+        public final HistoryTag localEventTag = new HistoryTag();
 
         public HistoryItem() {
         }
         
         public HistoryItem(long time, Parcel src) {
             this.time = time;
+            numReadInts = 2;
             readFromParcel(src);
         }
         
@@ -563,14 +622,20 @@
                     | ((((int)batteryVoltage)<<16)&0xffff0000);
             dest.writeInt(bat);
             dest.writeInt(states);
+            if (wakelockTag != null) {
+                dest.writeInt(1);
+                wakelockTag.writeToParcel(dest, flags);
+            } else {
+                dest.writeInt(0);
+            }
             if (cmd == CMD_EVENT) {
                 dest.writeInt(eventCode);
-                dest.writeInt(eventUid);
-                dest.writeString(eventName);
+                eventTag.writeToParcel(dest, flags);
             }
         }
 
         public void readFromParcel(Parcel src) {
+            int start = src.dataPosition();
             int bat = src.readInt();
             cmd = (byte)(bat&0xff);
             batteryLevel = (byte)((bat>>8)&0xff);
@@ -581,14 +646,21 @@
             batteryTemperature = (short)(bat&0xffff);
             batteryVoltage = (char)((bat>>16)&0xffff);
             states = src.readInt();
+            if (src.readInt() != 0) {
+                wakelockTag = localWakelockTag;
+                wakelockTag.readFromParcel(src);
+            } else {
+                wakelockTag = null;
+            }
             if (cmd == CMD_EVENT) {
                 eventCode = src.readInt();
-                eventUid = src.readInt();
-                eventName = src.readString();
-                eventNameIdx = 0;
+                eventTag = localEventTag;
+                eventTag.readFromParcel(src);
             } else {
                 eventCode = EVENT_NONE;
+                eventTag = null;
             }
+            numReadInts += (src.dataPosition()-start)/4;
         }
 
         public void clear() {
@@ -601,9 +673,9 @@
             batteryTemperature = 0;
             batteryVoltage = 0;
             states = 0;
+            wakelockTag = null;
             eventCode = EVENT_NONE;
-            eventUid = 0;
-            eventName = null;
+            eventTag = null;
         }
         
         public void setTo(HistoryItem o) {
@@ -616,10 +688,19 @@
             batteryTemperature = o.batteryTemperature;
             batteryVoltage = o.batteryVoltage;
             states = o.states;
+            if (o.wakelockTag != null) {
+                wakelockTag = localWakelockTag;
+                wakelockTag.setTo(o.wakelockTag);
+            } else {
+                wakelockTag = null;
+            }
             eventCode = o.eventCode;
-            eventUid = o.eventUid;
-            eventName = o.eventName;
-            eventNameIdx = o.eventNameIdx;
+            if (o.eventTag != null) {
+                eventTag = localEventTag;
+                eventTag.setTo(o.eventTag);
+            } else {
+                eventTag = null;
+            }
         }
 
         public void setTo(long time, byte cmd, int eventCode, int eventUid, String eventName,
@@ -627,9 +708,12 @@
             this.time = time;
             this.cmd = cmd;
             this.eventCode = eventCode;
-            this.eventUid = eventUid;
-            this.eventName = eventName;
-            this.eventNameIdx = 0;
+            if (eventCode != EVENT_NONE) {
+                eventTag = localEventTag;
+                eventTag.setTo(eventName, eventUid);
+            } else {
+                eventTag = null;
+            }
             batteryLevel = o.batteryLevel;
             batteryStatus = o.batteryStatus;
             batteryHealth = o.batteryHealth;
@@ -637,6 +721,12 @@
             batteryTemperature = o.batteryTemperature;
             batteryVoltage = o.batteryVoltage;
             states = o.states;
+            if (o.wakelockTag != null) {
+                wakelockTag = localWakelockTag;
+                wakelockTag.setTo(o.wakelockTag);
+            } else {
+                wakelockTag = null;
+            }
         }
 
         public boolean sameNonEvent(HistoryItem o) {
@@ -650,13 +740,26 @@
         }
 
         public boolean same(HistoryItem o) {
-            if (!sameNonEvent(o) || eventCode != o.eventCode || eventUid != o.eventUid) {
+            if (!sameNonEvent(o) || eventCode != o.eventCode) {
                 return false;
             }
-            if (eventName == o.eventName) {
-                return true;
+            if (wakelockTag != o.wakelockTag) {
+                if (wakelockTag == null || o.wakelockTag == null) {
+                    return false;
+                }
+                if (!wakelockTag.equals(o.wakelockTag)) {
+                    return false;
+                }
             }
-            return eventName != null && o.eventName != null && eventName.equals(o.eventName);
+            if (eventTag != o.eventTag) {
+                if (eventTag == null || o.eventTag == null) {
+                    return false;
+                }
+                if (!eventTag.equals(o.eventTag)) {
+                    return false;
+                }
+            }
+            return true;
         }
     }
     
@@ -688,11 +791,19 @@
         }
     }
     
+    public abstract int getHistoryTotalSize();
+
+    public abstract int getHistoryUsedSize();
+
     public abstract boolean startIteratingHistoryLocked();
 
     public abstract int getHistoryStringPoolSize();
 
-    public abstract String getHistoryStringPoolItem(int index);
+    public abstract int getHistoryStringPoolBytes();
+
+    public abstract String getHistoryTagPoolString(int index);
+
+    public abstract int getHistoryTagPoolUid(int index);
 
     public abstract boolean getNextHistoryLocked(HistoryItem out);
 
@@ -1746,14 +1857,14 @@
         
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Signal levels: ");
+        sb.append("  Signal levels:");
         didOne = false;
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             final long time = getPhoneSignalStrengthTime(i, batteryRealtime, which);
             if (time == 0) {
                 continue;
             }
-            if (didOne) sb.append(", ");
+            sb.append("\n    ");
             didOne = true;
             sb.append(SignalStrength.SIGNAL_STRENGTH_NAMES[i]);
             sb.append(" ");
@@ -1764,7 +1875,7 @@
             sb.append(getPhoneSignalStrengthCount(i, which));
             sb.append("x");
         }
-        if (!didOne) sb.append("No activity");
+        if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
         sb.setLength(0);
@@ -1775,14 +1886,14 @@
 
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Radio types: ");
+        sb.append("  Radio types:");
         didOne = false;
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
             final long time = getPhoneDataConnectionTime(i, batteryRealtime, which);
             if (time == 0) {
                 continue;
             }
-            if (didOne) sb.append(", ");
+            sb.append("\n    ");
             didOne = true;
             sb.append(DATA_CONNECTION_NAMES[i]);
             sb.append(" ");
@@ -1793,7 +1904,7 @@
             sb.append(getPhoneDataConnectionCount(i, which));
             sb.append("x");
         }
-        if (!didOne) sb.append("No activity");
+        if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
         sb.setLength(0);
@@ -2259,21 +2370,30 @@
         }
     }
 
-    static void printBitDescriptions(PrintWriter pw, int oldval, int newval,
+    static void printBitDescriptions(PrintWriter pw, int oldval, int newval, HistoryTag wakelockTag,
             BitDescription[] descriptions, boolean longNames) {
         int diff = oldval ^ newval;
         if (diff == 0) return;
+        boolean didWake = false;
         for (int i=0; i<descriptions.length; i++) {
             BitDescription bd = descriptions[i];
-            int mask = bd.mask;
-            if (bd.shift > 0) {
-                mask <<= bd.shift;
-            }
-            if ((diff&mask) != 0) {
+            if ((diff&bd.mask) != 0) {
                 pw.print(longNames ? " " : ",");
                 if (bd.shift < 0) {
-                    pw.print((newval&mask) != 0 ? "+" : "-");
+                    pw.print((newval&bd.mask) != 0 ? "+" : "-");
                     pw.print(longNames ? bd.name : bd.shortName);
+                    if (bd.mask == HistoryItem.STATE_WAKE_LOCK_FLAG && wakelockTag != null) {
+                        didWake = true;
+                        pw.print("=");
+                        if (longNames) {
+                            UserHandle.formatUid(pw, wakelockTag.uid);
+                            pw.print(":\"");
+                            pw.print(wakelockTag.string);
+                            pw.print("\"");
+                        } else {
+                            pw.print(wakelockTag.poolIdx);
+                        }
+                    }
                 } else {
                     pw.print(longNames ? bd.name : bd.shortName);
                     pw.print("=");
@@ -2286,6 +2406,17 @@
                 }
             }
         }
+        if (!didWake && wakelockTag != null) {
+            pw.print(longNames ? "wake_lock=" : "w=");
+            if (longNames) {
+                UserHandle.formatUid(pw, wakelockTag.uid);
+                pw.print(":\"");
+                pw.print(wakelockTag.string);
+                pw.print("\"");
+            } else {
+                pw.print(wakelockTag.poolIdx);
+            }
+        }
     }
     
     public void prepareForDumpLocked() {
@@ -2305,7 +2436,9 @@
             if (!checkin) {
                 pw.print("  ");
                 TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
-                pw.print(" ");
+                pw.print(" (");
+                pw.print(rec.numReadInts);
+                pw.print(") ");
             } else {
                 if (lastTime < 0) {
                     pw.print("@");
@@ -2427,7 +2560,7 @@
                     pw.print(checkin ? ",Bv=" : " volt=");
                     pw.print(oldVolt);
                 }
-                printBitDescriptions(pw, oldState, rec.states,
+                printBitDescriptions(pw, oldState, rec.states, rec.wakelockTag,
                         HISTORY_STATE_DESCRIPTIONS, !checkin);
                 if (rec.eventCode != HistoryItem.EVENT_NONE) {
                     switch (rec.eventCode) {
@@ -2450,15 +2583,12 @@
                             break;
                     }
                     if (checkin) {
-                        pw.print(rec.eventUid);
+                        pw.print(rec.eventTag.poolIdx);
                     } else {
-                        UserHandle.formatUid(pw, rec.eventUid);
-                    }
-                    pw.print(":");
-                    if (checkin) {
-                        pw.print(rec.eventNameIdx);
-                    } else {
-                        pw.print(rec.eventName);
+                        UserHandle.formatUid(pw, rec.eventTag.uid);
+                        pw.print(":\"");
+                        pw.print(rec.eventTag.string);
+                        pw.print("\"");
                     }
                 }
                 pw.println();
@@ -2467,6 +2597,33 @@
         }
     }
 
+    private void printSizeValue(PrintWriter pw, long size) {
+        float result = size;
+        String suffix = "";
+        if (result >= 10*1024) {
+            suffix = "KB";
+            result = result / 1024;
+        }
+        if (result >= 10*1024) {
+            suffix = "MB";
+            result = result / 1024;
+        }
+        if (result >= 10*1024) {
+            suffix = "GB";
+            result = result / 1024;
+        }
+        if (result >= 10*1024) {
+            suffix = "TB";
+            result = result / 1024;
+        }
+        if (result >= 10*1024) {
+            suffix = "PB";
+            result = result / 1024;
+        }
+        pw.print((int)result);
+        pw.print(suffix);
+    }
+
     /**
      * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
      *
@@ -2480,24 +2637,42 @@
         long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
 
         final HistoryItem rec = new HistoryItem();
+        final long historyTotalSize = getHistoryTotalSize();
+        final long historyUsedSize = getHistoryUsedSize();
         if (startIteratingHistoryLocked()) {
-            pw.println("Battery History:");
-            HistoryPrinter hprinter = new HistoryPrinter();
-            while (getNextHistoryLocked(rec)) {
-                hprinter.printNextItem(pw, rec, now, false);
+            try {
+                pw.print("Battery History (");
+                pw.print((100*historyUsedSize)/historyTotalSize);
+                pw.print("% used, ");
+                printSizeValue(pw, historyUsedSize);
+                pw.print(" used of ");
+                printSizeValue(pw, historyTotalSize);
+                pw.print(", ");
+                pw.print(getHistoryStringPoolSize());
+                pw.print(" strings using ");
+                printSizeValue(pw, getHistoryStringPoolBytes());
+                pw.println("):");
+                HistoryPrinter hprinter = new HistoryPrinter();
+                while (getNextHistoryLocked(rec)) {
+                    hprinter.printNextItem(pw, rec, now, false);
+                }
+                pw.println();
+            } finally {
+                finishIteratingHistoryLocked();
             }
-            finishIteratingHistoryLocked();
-            pw.println("");
         }
 
         if (startIteratingOldHistoryLocked()) {
-            pw.println("Old battery History:");
-            HistoryPrinter hprinter = new HistoryPrinter();
-            while (getNextOldHistoryLocked(rec)) {
-                hprinter.printNextItem(pw, rec, now, false);
+            try {
+                pw.println("Old battery History:");
+                HistoryPrinter hprinter = new HistoryPrinter();
+                while (getNextOldHistoryLocked(rec)) {
+                    hprinter.printNextItem(pw, rec, now, false);
+                }
+                pw.println();
+            } finally {
+                finishIteratingOldHistoryLocked();
             }
-            finishIteratingOldHistoryLocked();
-            pw.println("");
         }
 
         if (historyOnly) {
@@ -2553,21 +2728,26 @@
         if (includeHistory || historyOnly) {
             final HistoryItem rec = new HistoryItem();
             if (startIteratingHistoryLocked()) {
-                for (int i=0; i<getHistoryStringPoolSize(); i++) {
-                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
-                    pw.print(HISTORY_STRING_POOL); pw.print(',');
-                    pw.print(i);
-                    pw.print(',');
-                    pw.print(getHistoryStringPoolItem(i));
-                    pw.println();
+                try {
+                    for (int i=0; i<getHistoryStringPoolSize(); i++) {
+                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                        pw.print(HISTORY_STRING_POOL); pw.print(',');
+                        pw.print(i);
+                        pw.print(',');
+                        pw.print(getHistoryTagPoolString(i));
+                        pw.print(',');
+                        pw.print(getHistoryTagPoolUid(i));
+                        pw.println();
+                    }
+                    HistoryPrinter hprinter = new HistoryPrinter();
+                    while (getNextHistoryLocked(rec)) {
+                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                        pw.print(HISTORY_DATA); pw.print(',');
+                        hprinter.printNextItem(pw, rec, now, true);
+                    }
+                } finally {
+                    finishIteratingHistoryLocked();
                 }
-                HistoryPrinter hprinter = new HistoryPrinter();
-                while (getNextHistoryLocked(rec)) {
-                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
-                    pw.print(HISTORY_DATA); pw.print(',');
-                    hprinter.printNextItem(pw, rec, now, true);
-                }
-                finishIteratingHistoryLocked();
             }
         }
 
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 5275bc0..b65eac7 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -169,7 +169,7 @@
      * @param dialogIconRes The icon, as a resource ID.
      */
     public void setDialogIcon(int dialogIconRes) {
-        mDialogIcon = getContext().getResources().getDrawable(dialogIconRes);
+        mDialogIcon = getContext().getDrawable(dialogIconRes);
     }
     
     /**
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 76fccc7..144c909 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -561,7 +561,7 @@
         if (imageView != null) {
             if (mIconResId != 0 || mIcon != null) {
                 if (mIcon == null) {
-                    mIcon = getContext().getResources().getDrawable(mIconResId);
+                    mIcon = getContext().getDrawable(mIconResId);
                 }
                 if (mIcon != null) {
                     imageView.setImageDrawable(mIcon);
@@ -694,7 +694,7 @@
      */
     public void setIcon(int iconResId) {
         mIconResId = iconResId;
-        setIcon(mContext.getResources().getDrawable(iconResId));
+        setIcon(mContext.getDrawable(iconResId));
     }
 
     /**
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 74b9463..3d6f8e6 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -145,7 +145,7 @@
             }
         } else {
             try {
-                drawable = mContext.getResources().getDrawable(mResourceId);
+                drawable = mContext.getDrawable(mResourceId);
                 drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
                         drawable.getIntrinsicHeight());
             } catch (Exception e) {
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index da9ba5a..fd3f9b3 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -552,7 +552,8 @@
         return false;
     }
 
-    private static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
+    /** @hide */
+    public static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
         ArrayMap<Animator, AnimationInfo> runningAnimators = sRunningAnimators.get();
         if (runningAnimators == null) {
             runningAnimators = new ArrayMap<Animator, AnimationInfo>();
@@ -1077,6 +1078,9 @@
         if (view == null) {
             return;
         }
+        if (!isValidTarget(view, view.getId())) {
+            return;
+        }
         boolean isListViewItem = false;
         if (view.getParent() instanceof ListView) {
             isListViewItem = true;
@@ -1467,6 +1471,10 @@
         mCanRemoveViews = canRemoveViews;
     }
 
+    public boolean canRemoveViews() {
+        return mCanRemoveViews;
+    }
+
     @Override
     public String toString() {
         return toString("");
@@ -1629,9 +1637,10 @@
      * animation should be canceled or a new animation noop'd. The structure holds
      * information about the state that an animation is going to, to be compared to
      * end state of a new animation.
+     * @hide
      */
-    private static class AnimationInfo {
-        View view;
+    public static class AnimationInfo {
+        public View view;
         String name;
         TransitionValues values;
 
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index ed75850..aaa8b8c 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -91,7 +91,8 @@
     private static final String TAG_1995 = "blink";
     private static final String TAG_REQUEST_FOCUS = "requestFocus";
 
-    private static final String ATTR_THEME = "theme";
+    private static final int[] ATTRS_THEME = new int[] {
+            com.android.internal.R.attr.theme };
 
     /**
      * Hook to allow clients of the LayoutInflater to restrict the set of Views that are allowed
@@ -689,10 +690,12 @@
         }
 
         // Apply a theme wrapper, if requested.
-        final int themeResId = attrs.getAttributeResourceValue(null, ATTR_THEME, 0);
+        final TypedArray ta = viewContext.obtainStyledAttributes(attrs, ATTRS_THEME);
+        final int themeResId = ta.getResourceId(0, 0);
         if (themeResId != 0) {
             viewContext = new ContextThemeWrapper(viewContext, themeResId);
         }
+        ta.recycle();
 
         if (name.equals(TAG_1995)) {
             // Let's party like it's 1995!
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index bb7ed41..063a08d 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -140,7 +140,7 @@
         if ((resourceId & 0xff000000) == 0x01000000) {
             icon.mSystemIconResourceId = resourceId;
         } else {
-            icon.loadResource(context.getResources(), resourceId);
+            icon.loadResource(context, context.getResources(), resourceId);
         }
         return icon;
     }
@@ -198,7 +198,7 @@
         }
 
         PointerIcon icon = new PointerIcon(STYLE_CUSTOM);
-        icon.loadResource(resources, resourceId);
+        icon.loadResource(null, resources, resourceId);
         return icon;
     }
 
@@ -224,7 +224,7 @@
 
         PointerIcon result = new PointerIcon(mStyle);
         result.mSystemIconResourceId = mSystemIconResourceId;
-        result.loadResource(context.getResources(), mSystemIconResourceId);
+        result.loadResource(context, context.getResources(), mSystemIconResourceId);
         return result;
     }
 
@@ -373,7 +373,7 @@
         return true;
     }
 
-    private void loadResource(Resources resources, int resourceId) {
+    private void loadResource(Context context, Resources resources, int resourceId) {
         XmlResourceParser parser = resources.getXml(resourceId);
         final int bitmapRes;
         final float hotSpotX;
@@ -397,7 +397,12 @@
             throw new IllegalArgumentException("<pointer-icon> is missing bitmap attribute.");
         }
 
-        Drawable drawable = resources.getDrawable(bitmapRes);
+        Drawable drawable;
+        if (context == null) {
+            drawable = resources.getDrawable(bitmapRes);
+        } else {
+            drawable = context.getDrawable(bitmapRes);
+        }
         if (!(drawable instanceof BitmapDrawable)) {
             throw new IllegalArgumentException("<pointer-icon> bitmap attribute must "
                     + "refer to a bitmap drawable.");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 55dcbb2..97a1f21 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -177,13 +177,13 @@
      * Equivalent to calling hide().
      * Updates the value set during Surface creation (see {@link #HIDDEN}).
      */
-    public static final int SURFACE_HIDDEN = 0x01;
+    private static final int SURFACE_HIDDEN = 0x01;
 
     /**
      * Surface flag: composite without blending when possible.
      * Updates the value set during Surface creation (see {@link #OPAQUE}).
      */
-    public static final int SURFACE_OPAQUE = 0x02;
+    private static final int SURFACE_OPAQUE = 0x02;
 
 
     /* built-in physical display ids (keep in sync with ISurfaceComposer.h)
@@ -191,13 +191,13 @@
 
     /**
      * Built-in physical display id: Main display.
-     * Use only with {@link SurfaceControl#getBuiltInDisplay()}.
+     * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
      */
     public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
 
     /**
      * Built-in physical display id: Attached HDMI display.
-     * Use only with {@link SurfaceControl#getBuiltInDisplay()}.
+     * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
      */
     public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
 
@@ -369,18 +369,6 @@
         nativeSetMatrix(mNativeObject, dsdx, dtdx, dsdy, dtdy);
     }
 
-    /**
-     * Sets and clears flags, such as {@link #SURFACE_HIDDEN}.  The new value will be:
-     * <p>
-     *   <code>newFlags = (oldFlags & ~mask) | (flags & mask)</code>
-     * <p>
-     * Note this does not take the same set of flags as the constructor.
-     */
-    public void setFlags(int flags, int mask) {
-        checkNotReleased();
-        nativeSetFlags(mNativeObject, flags, mask);
-    }
-
     public void setWindowCrop(Rect crop) {
         checkNotReleased();
         if (crop != null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 239eda4..518908f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -665,6 +665,7 @@
  * @attr ref android.R.styleable#View_scrollbarTrackVertical
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
+ * @attr ref android.R.styleable#View_sharedElementName
  * @attr ref android.R.styleable#View_soundEffectsEnabled
  * @attr ref android.R.styleable#View_tag
  * @attr ref android.R.styleable#View_textAlignment
@@ -2325,7 +2326,18 @@
 
     /* End of masks for mPrivateFlags2 */
 
-    /* Masks for mPrivateFlags3 */
+    /**
+     * Masks for mPrivateFlags3, as generated by dumpFlags():
+     *
+     * |-------|-------|-------|-------|
+     *                                 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM
+     *                                1  PFLAG3_VIEW_IS_ANIMATING_ALPHA
+     *                               1   PFLAG3_IS_LAID_OUT
+     *                              1    PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT
+     *                             1     PFLAG3_CALLED_SUPER
+     *                            1      PFLAG3_PROJECT_BACKGROUND
+     * |-------|-------|-------|-------|
+     */
 
     /**
      * Flag indicating that view has a transform animation set on it. This is used to track whether
@@ -2359,6 +2371,11 @@
      */
     static final int PFLAG3_CALLED_SUPER = 0x10;
 
+    /**
+     * Flag indicating that the background of this view will be drawn into a
+     * display list and projected onto the closest parent projection surface.
+     */
+    static final int PFLAG3_PROJECT_BACKGROUND = 0x20;
 
     /* End of masks for mPrivateFlags3 */
 
@@ -3225,6 +3242,15 @@
     @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_")
     private Drawable mBackground;
 
+    /**
+     * Display list used for backgrounds.
+     * <p>
+     * When non-null and valid, this is expected to contain an up-to-date copy
+     * of the background drawable. It is cleared on temporary detach and reset
+     * on cleanup.
+     */
+    private DisplayList mBackgroundDisplayList;
+
     private int mBackgroundResource;
     private boolean mBackgroundSizeChanged;
 
@@ -3503,6 +3529,13 @@
     private Bitmap mDrawingCache;
     private Bitmap mUnscaledDrawingCache;
 
+    /**
+     * Display list used for the View content.
+     * <p>
+     * When non-null and valid, this is expected to contain an up-to-date copy
+     * of the View content. It is cleared on temporary detach and reset on
+     * cleanup.
+     */
     DisplayList mDisplayList;
 
     /**
@@ -4006,6 +4039,9 @@
                 case R.styleable.View_accessibilityLiveRegion:
                     setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
                     break;
+                case R.styleable.View_sharedElementName:
+                    setSharedElementName(a.getString(attr));
+                    break;
             }
         }
 
@@ -13688,12 +13724,20 @@
         if (mDisplayList != null) {
             mDisplayList.clear();
         }
+
+        if (mBackgroundDisplayList != null) {
+            mBackgroundDisplayList.clear();
+        }
     }
 
     private void resetDisplayList() {
         if (mDisplayList != null) {
             mDisplayList.reset();
         }
+
+        if (mBackgroundDisplayList != null) {
+            mBackgroundDisplayList.reset();
+        }
     }
 
     /**
@@ -14721,24 +14765,7 @@
         int saveCount;
 
         if (!dirtyOpaque) {
-            final Drawable background = mBackground;
-            if (background != null) {
-                final int scrollX = mScrollX;
-                final int scrollY = mScrollY;
-
-                if (mBackgroundSizeChanged) {
-                    background.setBounds(0, 0,  mRight - mLeft, mBottom - mTop);
-                    mBackgroundSizeChanged = false;
-                }
-
-                if ((scrollX | scrollY) == 0) {
-                    background.draw(canvas);
-                } else {
-                    canvas.translate(scrollX, scrollY);
-                    background.draw(canvas);
-                    canvas.translate(-scrollX, -scrollY);
-                }
-            }
+            drawBackground(canvas);
         }
 
         // skip step 2 & 5 if possible (common case)
@@ -14905,6 +14932,93 @@
     }
 
     /**
+     * Draws the background onto the specified canvas.
+     *
+     * @param canvas Canvas on which to draw the background
+     */
+    private void drawBackground(Canvas canvas) {
+        final Drawable background = mBackground;
+        if (background == null) {
+            return;
+        }
+
+        if (mBackgroundSizeChanged) {
+            // We should see the background invalidate itself, but just to be
+            // careful we're going to clear the display list and force redraw.
+            if (mBackgroundDisplayList != null) {
+                mBackgroundDisplayList.clear();
+            }
+
+            background.setBounds(0, 0,  mRight - mLeft, mBottom - mTop);
+            mBackgroundSizeChanged = false;
+        }
+
+
+        // Attempt to use a display list if requested.
+        if (canvas != null && canvas.isHardwareAccelerated()) {
+            mBackgroundDisplayList = getDrawableDisplayList(background, mBackgroundDisplayList);
+
+            final DisplayList displayList = mBackgroundDisplayList;
+            if (displayList != null && displayList.isValid()) {
+                setBackgroundDisplayListProperties(displayList);
+                ((HardwareCanvas) canvas).drawDisplayList(displayList);
+                return;
+            }
+        }
+
+        final int scrollX = mScrollX;
+        final int scrollY = mScrollY;
+        if ((scrollX | scrollY) == 0) {
+            background.draw(canvas);
+        } else {
+            canvas.translate(scrollX, scrollY);
+            background.draw(canvas);
+            canvas.translate(-scrollX, -scrollY);
+        }
+    }
+
+    /**
+     * Set up background drawable display list properties.
+     *
+     * @param displayList Valid display list for the background drawable
+     */
+    private void setBackgroundDisplayListProperties(DisplayList displayList) {
+        displayList.setProjectBackwards((mPrivateFlags3 & PFLAG3_PROJECT_BACKGROUND) != 0);
+        displayList.setTranslationX(mScrollX);
+        displayList.setTranslationY(mScrollY);
+    }
+
+    /**
+     * Creates a new display list or updates the existing display list for the
+     * specified Drawable.
+     *
+     * @param drawable Drawable for which to create a display list
+     * @param displayList Existing display list, or {@code null}
+     * @return A valid display list for the specified drawable
+     */
+    private static DisplayList getDrawableDisplayList(Drawable drawable, DisplayList displayList) {
+        if (displayList != null && displayList.isValid()) {
+            return displayList;
+        }
+
+        if (displayList == null) {
+            displayList = DisplayList.create(drawable.getClass().getName());
+        }
+
+        final Rect bounds = drawable.getBounds();
+        final int width = bounds.width();
+        final int height = bounds.height();
+        final HardwareCanvas canvas = displayList.start(width, height);
+        drawable.draw(canvas);
+        displayList.end();
+
+        // Set up drawable properties that are view-independent.
+        displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        displayList.setClipToBounds(false);
+        return displayList;
+    }
+
+    /**
      * Returns the overlay for this view, creating it if it does not yet exist.
      * Adding drawables to the overlay will cause them to be displayed whenever
      * the view itself is redrawn. Objects in the overlay should be actively
@@ -15245,14 +15359,22 @@
      *
      * @param drawable the drawable to invalidate
      */
+    @Override
     public void invalidateDrawable(Drawable drawable) {
         if (verifyDrawable(drawable)) {
-            final Rect dirty = drawable.getBounds();
-            final int scrollX = mScrollX;
-            final int scrollY = mScrollY;
+            if (drawable == mBackground && mBackgroundDisplayList != null) {
+                // If we're using a background display list, we only need to
+                // invalidate the display list and notify the parent to redraw.
+                mBackgroundDisplayList.clear();
+                invalidateViewProperty(true, false);
+            } else {
+                final Rect dirty = drawable.getBounds();
+                final int scrollX = mScrollX;
+                final int scrollY = mScrollY;
 
-            invalidate(dirty.left + scrollX, dirty.top + scrollY,
-                    dirty.right + scrollX, dirty.bottom + scrollY);
+                invalidate(dirty.left + scrollX, dirty.top + scrollY,
+                        dirty.right + scrollX, dirty.bottom + scrollY);
+            }
         }
     }
 
@@ -15399,7 +15521,7 @@
      * @see Drawable#setState(int[])
      */
     protected void drawableStateChanged() {
-        Drawable d = mBackground;
+        final Drawable d = mBackground;
         if (d != null && d.isStateful()) {
             d.setState(getDrawableState());
         }
@@ -15584,7 +15706,7 @@
 
         Drawable d= null;
         if (resid != 0) {
-            d = mResources.getDrawable(resid);
+            d = mContext.getDrawable(resid);
         }
         setBackground(d);
 
@@ -18754,6 +18876,35 @@
     }
 
     /**
+     * Specifies that the shared name of the View to be shared with another Activity.
+     * When transitioning between Activities, the name links a UI element in the starting
+     * Activity to UI element in the called Activity. Names should be unique in the
+     * View hierarchy.
+     *
+     * @param sharedElementName The cross-Activity View identifier. The called Activity will use
+     *                 the name to match the location with a View in its layout.
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     */
+    public void setSharedElementName(String sharedElementName) {
+        setTagInternal(com.android.internal.R.id.shared_element_name, sharedElementName);
+    }
+
+    /**
+     * Returns the shared name of the View to be shared with another Activity.
+     * When transitioning between Activities, the name links a UI element in the starting
+     * Activity to UI element in the called Activity. Names should be unique in the
+     * View hierarchy.
+     *
+     * <p>This returns null if the View is not a shared element or the name if it is.</p>
+     *
+     * @return The name used for this View for cross-Activity transitions or null if
+     * this View has not been identified as shared.
+     */
+    public String getSharedElementName() {
+        return (String) getTag(com.android.internal.R.id.shared_element_name);
+    }
+
+    /**
      * Interface definition for a callback to be invoked when a hardware key event is
      * dispatched to this view. The callback will be invoked before the key event is
      * given to the view. This is only useful for hardware keyboards; a software input
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b91091f..73b108f 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -360,6 +360,10 @@
      */
     static final int FLAG_ISOLATED_Z_VOLUME = 0x1000000;
 
+    static final int FLAG_IS_TRANSITION_GROUP = 0x2000000;
+
+    static final int FLAG_IS_TRANSITION_GROUP_SET = 0x4000000;
+
     /**
      * Indicates which types of drawing caches are to be kept in memory.
      * This field should be made private, so it is hidden from the SDK.
@@ -556,6 +560,9 @@
                 case R.styleable.ViewGroup_layoutMode:
                     setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
                     break;
+                case R.styleable.ViewGroup_transitionGroup:
+                    setTransitionGroup(a.getBoolean(attr, false));
+                    break;
             }
         }
 
@@ -2288,6 +2295,41 @@
     }
 
     /**
+     * Returns true if this ViewGroup should be considered as a single entity for removal
+     * when executing an Activity transition. If this is false, child elements will move
+     * individually during the transition.
+     * @return True if the ViewGroup should be acted on together during an Activity transition.
+     * The default value is false when the background is null and true when the background
+     * is not null.
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     */
+    public boolean isTransitionGroup() {
+        if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
+            return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
+        } else {
+            return getBackground() != null;
+        }
+    }
+
+    /**
+     * Changes whether or not this ViewGroup should be treated as a single entity during
+     * ActivityTransitions.
+     * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
+     *                          in Activity transitions. If false, the ViewGroup won't transition,
+     *                          only its children. If true, the entire ViewGroup will transition
+     *                          together.
+     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     */
+    public void setTransitionGroup(boolean isTransitionGroup) {
+        mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
+        if (isTransitionGroup) {
+            mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
+        } else {
+            mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
+        }
+    }
+
+    /**
      * {@inheritDoc}
      */
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5aa46f3..ccb85a6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2592,7 +2592,7 @@
                         R.attr.accessibilityFocusedDrawable, value, true);
                 if (resolved) {
                     mAttachInfo.mAccessibilityFocusDrawable =
-                        mView.mContext.getResources().getDrawable(value.resourceId);
+                        mView.mContext.getDrawable(value.resourceId);
                 }
             }
             return mAttachInfo.mAccessibilityFocusDrawable;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 2f62431..11740ab 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
@@ -1039,7 +1040,7 @@
      */
     public void setBackgroundDrawableResource(int resid)
     {
-        setBackgroundDrawable(mContext.getResources().getDrawable(resid));
+        setBackgroundDrawable(mContext.getDrawable(resid));
     }
 
     /**
@@ -1374,8 +1375,41 @@
     /**
      * Set options that can affect the transition behavior within this window.
      * @param options Options to set or null for none
+     * @hide
      */
-    public void setTransitionOptions(Bundle options) {
-        throw new UnsupportedOperationException();
+    public void setTransitionOptions(ActivityOptions options, SceneTransitionListener listener) {
+    }
+
+    /**
+     * A callback for Activity transitions to be told when the shared element is ready to be shown
+     * and start the transition to its target location.
+     * @hide
+     */
+    public interface SceneTransitionListener {
+        void enterSharedElement(Bundle transitionArgs);
+        void nullPendingTransition();
+        void convertFromTranslucent();
+        void convertToTranslucent();
+    }
+
+    /**
+     * Controls how the background fade is triggered. If fadeEarly is true, the Window background
+     * will fade in as soon as the shared elements are ready to switch. If fadeEarly is false,
+     * the background will fade only after the calling Activity's exit transition completes.
+     * By default, the Window will fade in when the calling Activity's exit transition completes.
+     *
+     * @param fadeEarly Set to true to fade out the exiting Activity as soon as the shared elements
+     *                  are transferred. Set to false to fade out the exiting Activity as soon as
+     *                  the shared element is transferred.
+     * @hide
+     */
+    public void setEarlyBackgroundTransition(boolean fadeEarly) {
+    }
+
+    /**
+     * Start the exit transition.
+     * @hide
+     */
+    public void startExitTransition(ActivityOptions activityOptions) {
     }
 }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4d8975c..13febe9 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1604,7 +1604,7 @@
     }
 
     private void useDefaultSelector() {
-        setSelector(getResources().getDrawable(
+        setSelector(getContext().getDrawable(
                 com.android.internal.R.drawable.list_selector_background));
     }
 
@@ -2616,7 +2616,7 @@
      * @attr ref android.R.styleable#AbsListView_listSelector
      */
     public void setSelector(int resID) {
-        setSelector(getResources().getDrawable(resID));
+        setSelector(getContext().getDrawable(resID));
     }
 
     public void setSelector(Drawable sel) {
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 3c88e94..5b80648 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -80,17 +80,17 @@
 
         mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial);
         if (mDial == null) {
-            mDial = r.getDrawable(com.android.internal.R.drawable.clock_dial);
+            mDial = context.getDrawable(com.android.internal.R.drawable.clock_dial);
         }
 
         mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour);
         if (mHourHand == null) {
-            mHourHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_hour);
+            mHourHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_hour);
         }
 
         mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute);
         if (mMinuteHand == null) {
-            mMinuteHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_minute);
+            mMinuteHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_minute);
         }
 
         mCalendar = new Time();
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 34cfea5..10e56c7 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -322,7 +322,7 @@
             CharSequence grpName, CharSequence description, boolean dangerous) {
         LayoutInflater inflater = (LayoutInflater)context.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        Drawable icon = context.getResources().getDrawable(dangerous
+        Drawable icon = context.getDrawable(dangerous
                 ? R.drawable.ic_bullet_key_permission : R.drawable.ic_text_dot);
         return getPermissionItemViewOld(context, inflater, grpName,
                 description, dangerous, icon);
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 259c66b..eb232fd 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -366,7 +366,7 @@
      * @attr ref android.R.styleable#PopupWindow_popupBackground
      */
     public void setDropDownBackgroundResource(int id) {
-        mPopup.setBackgroundDrawable(getResources().getDrawable(id));
+        mPopup.setBackgroundDrawable(getContext().getDrawable(id));
     }
     
     /**
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index c6be6dd..ea60abb 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -1029,7 +1029,7 @@
 
         @Override
         public void setSelectedDateVerticalBar(int resourceId) {
-            Drawable drawable = mDelegator.getResources().getDrawable(resourceId);
+            Drawable drawable = mDelegator.getContext().getDrawable(resourceId);
             setSelectedDateVerticalBar(drawable);
         }
 
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 78b1b75..1533510 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -123,7 +123,7 @@
 
         Drawable d = null;
         if (mCheckMarkResource != 0) {
-            d = getResources().getDrawable(mCheckMarkResource);
+            d = getContext().getDrawable(mCheckMarkResource);
         }
         setCheckMarkDrawable(d);
     }
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index b22088c..4298545 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -186,7 +186,7 @@
 
         Drawable d = null;
         if (mButtonResource != 0) {
-            d = getResources().getDrawable(mButtonResource);
+            d = getContext().getDrawable(mButtonResource);
         }
         setButtonDrawable(d);
     }
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 30752e0..fa37443 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -136,8 +136,8 @@
      */
     public EdgeEffect(Context context) {
         final Resources res = context.getResources();
-        mEdge = res.getDrawable(R.drawable.overscroll_edge);
-        mGlow = res.getDrawable(R.drawable.overscroll_glow);
+        mEdge = context.getDrawable(R.drawable.overscroll_edge);
+        mGlow = context.getDrawable(R.drawable.overscroll_glow);
 
         mEdgeHeight = mEdge.getIntrinsicHeight();
         mGlowHeight = mGlow.getIntrinsicHeight();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 11dbce8..ea62bbe 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1679,7 +1679,7 @@
 
     private void updateCursorPosition(int cursorIndex, int top, int bottom, float horizontal) {
         if (mCursorDrawable[cursorIndex] == null)
-            mCursorDrawable[cursorIndex] = mTextView.getResources().getDrawable(
+            mCursorDrawable[cursorIndex] = mTextView.getContext().getDrawable(
                     mTextView.mCursorDrawableRes);
 
         if (mTempRect == null) mTempRect = new Rect();
@@ -2969,7 +2969,7 @@
                 positionY += mContentView.getMeasuredHeight();
 
                 // Assumes insertion and selection handles share the same height
-                final Drawable handle = mTextView.getResources().getDrawable(
+                final Drawable handle = mTextView.getContext().getDrawable(
                         mTextView.mTextSelectHandleRes);
                 positionY += handle.getIntrinsicHeight();
             }
@@ -3546,7 +3546,7 @@
 
         private InsertionHandleView getHandle() {
             if (mSelectHandleCenter == null) {
-                mSelectHandleCenter = mTextView.getResources().getDrawable(
+                mSelectHandleCenter = mTextView.getContext().getDrawable(
                         mTextView.mTextSelectHandleRes);
             }
             if (mHandle == null) {
@@ -3592,11 +3592,11 @@
 
         private void initDrawables() {
             if (mSelectHandleLeft == null) {
-                mSelectHandleLeft = mTextView.getContext().getResources().getDrawable(
+                mSelectHandleLeft = mTextView.getContext().getDrawable(
                         mTextView.mTextSelectHandleLeftRes);
             }
             if (mSelectHandleRight == null) {
-                mSelectHandleRight = mTextView.getContext().getResources().getDrawable(
+                mSelectHandleRight = mTextView.getContext().getDrawable(
                         mTextView.mTextSelectHandleRightRes);
             }
         }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 0f51fab..572302a 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -364,13 +364,13 @@
     @android.view.RemotableViewMethod
     public void setImageResource(int resId) {
         if (mUri != null || mResource != resId) {
+            final int oldWidth = mDrawableWidth;
+            final int oldHeight = mDrawableHeight;
+
             updateDrawable(null);
             mResource = resId;
             mUri = null;
 
-            final int oldWidth = mDrawableWidth;
-            final int oldHeight = mDrawableHeight;
-
             resolveUri();
 
             if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
@@ -570,7 +570,7 @@
     }
 
     /** Return the view's optional matrix. This is applied to the
-        view's drawable when it is drawn. If there is not matrix,
+        view's drawable when it is drawn. If there is no matrix,
         this method will return an identity matrix.
         Do not change this matrix in place but make a copy.
         If you want a different matrix applied to the drawable,
@@ -642,7 +642,7 @@
 
         if (mResource != 0) {
             try {
-                d = rsrc.getDrawable(mResource);
+                d = mContext.getDrawable(mResource);
             } catch (Exception e) {
                 Log.w("ImageView", "Unable to find resource: " + mResource, e);
                 // Don't try again.
@@ -655,7 +655,7 @@
                     // Load drawable through Resources, to get the source density information
                     ContentResolver.OpenResourceIdResult r =
                             mContext.getContentResolver().getResourceId(mUri);
-                    d = r.r.getDrawable(r.id);
+                    d = r.r.getDrawable(r.id, mContext.getTheme());
                 } catch (Exception e) {
                     Log.w("ImageView", "Unable to open content: " + mUri, e);
                 }
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index a4f758c..74b41c9 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -155,7 +155,7 @@
      */
     public void setImageToDefault() {
         if (mDefaultAvatar == null) {
-            mDefaultAvatar = getResources().getDrawable(R.drawable.ic_contact_picture);
+            mDefaultAvatar = mContext.getDrawable(R.drawable.ic_contact_picture);
         }
         setImageDrawable(mDefaultAvatar);
     }
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 3791258..1eedc5d 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1059,7 +1059,7 @@
 
         SpannableStringBuilder ssb = new SpannableStringBuilder("   "); // for the icon
         ssb.append(hintText);
-        Drawable searchIcon = getContext().getResources().getDrawable(getSearchIconId());
+        Drawable searchIcon = getContext().getDrawable(getSearchIconId());
         int textSize = (int) (mQueryTextView.getTextSize() * 1.25);
         searchIcon.setBounds(0, 0, textSize, textSize);
         ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index bdaaa01..64a1574 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -168,7 +168,7 @@
         // Lookup and set the expand action icon.
         TypedValue outTypedValue = new TypedValue();
         mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
-        Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId);
+        Drawable drawable = mContext.getDrawable(outTypedValue.resourceId);
         activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
         activityChooserView.setProvider(this);
 
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index eabe1a3..9601d4a 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -281,7 +281,7 @@
      * @attr ref android.R.styleable#Spinner_popupBackground
      */
     public void setPopupBackgroundResource(int resId) {
-        setPopupBackgroundDrawable(getContext().getResources().getDrawable(resId));
+        setPopupBackgroundDrawable(getContext().getDrawable(resId));
     }
 
     /**
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index c44d431..c8917e0 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -529,7 +529,7 @@
                 return drawable;
             }
             // Not cached, find it by resource ID
-            drawable = mProviderContext.getResources().getDrawable(resourceId);
+            drawable = mProviderContext.getDrawable(resourceId);
             // Stick it in the cache, using the URI as key
             storeInIconCache(drawableUri, drawable);
             return drawable;
@@ -563,7 +563,7 @@
                 OpenResourceIdResult r =
                     mProviderContext.getContentResolver().getResourceId(uri);
                 try {
-                    return r.r.getDrawable(r.id);
+                    return r.r.getDrawable(r.id, mContext.getTheme());
                 } catch (Resources.NotFoundException ex) {
                     throw new FileNotFoundException("Resource does not exist: " + uri);
                 }
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index c9a1ca4..2a5fb15 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -417,7 +417,7 @@
      * @attr ref android.R.styleable#Switch_track
      */
     public void setTrackResource(int resId) {
-        setTrackDrawable(getContext().getResources().getDrawable(resId));
+        setTrackDrawable(getContext().getDrawable(resId));
     }
 
     /**
@@ -453,7 +453,7 @@
      * @attr ref android.R.styleable#Switch_thumb
      */
     public void setThumbResource(int resId) {
-        setThumbDrawable(getContext().getResources().getDrawable(resId));
+        setThumbDrawable(getContext().getDrawable(resId));
     }
 
     /**
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 568b3e6..47a5449 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -120,28 +120,27 @@
         setChildrenDrawingOrderEnabled(true);
 
         final Context context = mContext;
-        final Resources resources = context.getResources();
 
         // Tests the target Sdk version, as set in the Manifest. Could not be set using styles.xml
         // in a values-v? directory which targets the current platform Sdk version instead.
         if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
             // Donut apps get old color scheme
             if (mLeftStrip == null) {
-                mLeftStrip = resources.getDrawable(
+                mLeftStrip = context.getDrawable(
                         com.android.internal.R.drawable.tab_bottom_left_v4);
             }
             if (mRightStrip == null) {
-                mRightStrip = resources.getDrawable(
+                mRightStrip = context.getDrawable(
                         com.android.internal.R.drawable.tab_bottom_right_v4);
             }
         } else {
             // Use modern color scheme for Eclair and beyond
             if (mLeftStrip == null) {
-                mLeftStrip = resources.getDrawable(
+                mLeftStrip = context.getDrawable(
                         com.android.internal.R.drawable.tab_bottom_left);
             }
             if (mRightStrip == null) {
-                mRightStrip = resources.getDrawable(
+                mRightStrip = context.getDrawable(
                         com.android.internal.R.drawable.tab_bottom_right);
             }
         }
@@ -246,7 +245,7 @@
      * divider.
      */
     public void setDividerDrawable(int resId) {
-        setDividerDrawable(getResources().getDrawable(resId));
+        setDividerDrawable(mContext.getDrawable(resId));
     }
     
     /**
@@ -267,7 +266,7 @@
      * left strip drawable
      */
     public void setLeftStripDrawable(int resId) {
-        setLeftStripDrawable(getResources().getDrawable(resId));
+        setLeftStripDrawable(mContext.getDrawable(resId));
     }
 
     /**
@@ -288,7 +287,7 @@
      * right strip drawable
      */
     public void setRightStripDrawable(int resId) {
-        setRightStripDrawable(getResources().getDrawable(resId));
+        setRightStripDrawable(mContext.getDrawable(resId));
     }
 
     /**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 15606a4..3be23b7 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2073,11 +2073,11 @@
      */
     @android.view.RemotableViewMethod
     public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) {
-        final Resources resources = getContext().getResources();
-        setCompoundDrawablesWithIntrinsicBounds(left != 0 ? resources.getDrawable(left) : null,
-                top != 0 ? resources.getDrawable(top) : null,
-                right != 0 ? resources.getDrawable(right) : null,
-                bottom != 0 ? resources.getDrawable(bottom) : null);
+        final Context context = getContext();
+        setCompoundDrawablesWithIntrinsicBounds(left != 0 ? context.getDrawable(left) : null,
+                top != 0 ? context.getDrawable(top) : null,
+                right != 0 ? context.getDrawable(right) : null,
+                bottom != 0 ? context.getDrawable(bottom) : null);
     }
 
     /**
@@ -2247,12 +2247,12 @@
     @android.view.RemotableViewMethod
     public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end,
             int bottom) {
-        final Resources resources = getContext().getResources();
+        final Context context = getContext();
         setCompoundDrawablesRelativeWithIntrinsicBounds(
-                start != 0 ? resources.getDrawable(start) : null,
-                top != 0 ? resources.getDrawable(top) : null,
-                end != 0 ? resources.getDrawable(end) : null,
-                bottom != 0 ? resources.getDrawable(bottom) : null);
+                start != 0 ? context.getDrawable(start) : null,
+                top != 0 ? context.getDrawable(top) : null,
+                end != 0 ? context.getDrawable(end) : null,
+                bottom != 0 ? context.getDrawable(bottom) : null);
     }
 
     /**
@@ -4385,8 +4385,8 @@
         if (error == null) {
             setError(null, null);
         } else {
-            Drawable dr = getContext().getResources().
-                getDrawable(com.android.internal.R.drawable.indicator_input_error);
+            Drawable dr = getContext().getDrawable(
+                    com.android.internal.R.drawable.indicator_input_error);
 
             dr.setBounds(0, 0, dr.getIntrinsicWidth(), dr.getIntrinsicHeight());
             setError(error, dr);
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 347f957..0a80495 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -1081,7 +1081,7 @@
 
         @Override
         public Tab setIcon(int resId) {
-            return setIcon(mContext.getResources().getDrawable(resId));
+            return setIcon(mContext.getDrawable(resId));
         }
 
         @Override
diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialog.java b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
index 8fc99c7..b0e0373 100644
--- a/core/java/com/android/internal/app/MediaRouteControllerDialog.java
+++ b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
@@ -256,13 +256,13 @@
     private Drawable getIconDrawable() {
         if (mRoute.isConnecting()) {
             if (mMediaRouteConnectingDrawable == null) {
-                mMediaRouteConnectingDrawable = getContext().getResources().getDrawable(
+                mMediaRouteConnectingDrawable = getContext().getDrawable(
                         R.drawable.ic_media_route_connecting_holo_dark);
             }
             return mMediaRouteConnectingDrawable;
         } else {
             if (mMediaRouteOnDrawable == null) {
-                mMediaRouteOnDrawable = getContext().getResources().getDrawable(
+                mMediaRouteOnDrawable = getContext().getDrawable(
                         R.drawable.ic_media_route_on_holo_dark);
             }
             return mMediaRouteOnDrawable;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7425445..68c41fa 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -87,7 +87,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 71 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 75 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -189,9 +189,12 @@
     final HistoryItem mHistoryLastWritten = new HistoryItem();
     final HistoryItem mHistoryLastLastWritten = new HistoryItem();
     final HistoryItem mHistoryReadTmp = new HistoryItem();
-    final HashMap<String, Integer> mHistoryStringPool = new HashMap<String, Integer>();
+    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<HistoryTag, Integer>();
     String[] mReadHistoryStrings;
-    int mNextHistoryStringIdx = 0;
+    int[] mReadHistoryUids;
+    int mReadHistoryChars;
+    int mNextHistoryTagIdx = 0;
+    int mNumHistoryTagChars = 0;
     int mHistoryBufferLastPos = -1;
     boolean mHistoryOverflow = false;
     long mLastHistoryTime = 0;
@@ -1486,18 +1489,43 @@
         mBtHeadset = headset;
     }
 
+    private int writeHistoryTag(HistoryTag tag) {
+        Integer idxObj = mHistoryTagPool.get(tag);
+        int idx;
+        if (idxObj != null) {
+            idx = idxObj;
+        } else {
+            idx = mNextHistoryTagIdx;
+            HistoryTag key = new HistoryTag();
+            key.setTo(tag);
+            tag.poolIdx = idx;
+            mHistoryTagPool.put(key, idx);
+            mNextHistoryTagIdx++;
+            mNumHistoryTagChars += key.string.length() + 1;
+        }
+        return idx;
+    }
+
+    private void readHistoryTag(int index, HistoryTag tag) {
+        tag.string = mReadHistoryStrings[index];
+        tag.uid = mReadHistoryUids[index];
+        tag.poolIdx = index;
+    }
+
     // Part of initial delta int that specifies the time delta.
-    static final int DELTA_TIME_MASK = 0x3ffff;
-    static final int DELTA_TIME_ABS = 0x3fffd;    // Following is an entire abs update.
-    static final int DELTA_TIME_INT = 0x3fffe;    // The delta is a following int
-    static final int DELTA_TIME_LONG = 0x3ffff;   // The delta is a following long
+    static final int DELTA_TIME_MASK = 0x1ffff;
+    static final int DELTA_TIME_LONG = 0x1ffff;   // The delta is a following long
+    static final int DELTA_TIME_INT = 0x1fffe;    // The delta is a following int
+    static final int DELTA_TIME_ABS = 0x1fffd;    // Following is an entire abs update.
     // Part of initial delta int holding the command code.
     static final int DELTA_CMD_MASK = 0x3;
-    static final int DELTA_CMD_SHIFT = 18;
+    static final int DELTA_CMD_SHIFT = 17;
     // Flag in delta int: a new battery level int follows.
-    static final int DELTA_BATTERY_LEVEL_FLAG = 1<<20;
+    static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
     // Flag in delta int: a new full state and battery status int follows.
-    static final int DELTA_STATE_FLAG = 1<<21;
+    static final int DELTA_STATE_FLAG = 0x00100000;
+    // Flag in delta int: contains a wakelock tag.
+    static final int DELTA_WAKELOCK_FLAG = 0x00200000;
     static final int DELTA_STATE_MASK = 0xffc00000;
 
     public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
@@ -1532,6 +1560,9 @@
         if (stateIntChanged) {
             firstToken |= DELTA_STATE_FLAG;
         }
+        if (cur.wakelockTag != null) {
+            firstToken |= DELTA_WAKELOCK_FLAG;
+        }
         dest.writeInt(firstToken);
         if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
                 + " deltaTime=" + deltaTime);
@@ -1562,20 +1593,19 @@
                     + " batteryPlugType=" + cur.batteryPlugType
                     + " states=0x" + Integer.toHexString(cur.states));
         }
+        if (cur.wakelockTag != null) {
+            int index = writeHistoryTag(cur.wakelockTag);
+            dest.writeInt(index);
+            if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
+                + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
+        }
         if (cur.cmd == HistoryItem.CMD_EVENT) {
-            Integer idxObj = mHistoryStringPool.get(cur.eventName);
-            int codeAndIndex = (cur.eventCode&0xffff);
-            int idx;
-            if (idxObj != null) {
-                idx = idxObj;
-            } else {
-                idx = mNextHistoryStringIdx;
-                mHistoryStringPool.put(cur.eventName, mNextHistoryStringIdx);
-                mNextHistoryStringIdx++;
-            }
-            codeAndIndex |= (idx<<16);
+            int index = writeHistoryTag(cur.eventTag);
+            int codeAndIndex = (cur.eventCode&0xffff) | (index<<16);
             dest.writeInt(codeAndIndex);
-            dest.writeInt(cur.eventUid);
+            if (DEBUG) Slog.i(TAG, "WRITE DELTA: event=" + cur.eventCode + " tag=#"
+                    + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
+                    + cur.eventTag.string);
         }
     }
 
@@ -1596,6 +1626,7 @@
         int firstToken = src.readInt();
         int deltaTimeToken = firstToken&DELTA_TIME_MASK;
         cur.cmd = (byte)((firstToken>>DELTA_CMD_SHIFT)&DELTA_CMD_MASK);
+        cur.numReadInts = 1;
         if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
                 + " deltaTimeToken=" + deltaTimeToken);
 
@@ -1603,16 +1634,20 @@
             cur.time += deltaTimeToken;
         } else if (deltaTimeToken == DELTA_TIME_ABS) {
             cur.time = src.readLong();
+            cur.numReadInts += 2;
+            if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
             cur.readFromParcel(src);
             return;
         } else if (deltaTimeToken == DELTA_TIME_INT) {
             int delta = src.readInt();
             cur.time += delta;
+            cur.numReadInts += 1;
             if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
         } else {
             long delta = src.readLong();
             if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + cur.time);
             cur.time += delta;
+            cur.numReadInts += 2;
         }
 
         if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
@@ -1620,6 +1655,7 @@
             cur.batteryLevel = (byte)((batteryLevelInt>>25)&0x7f);
             cur.batteryTemperature = (short)((batteryLevelInt<<7)>>21);
             cur.batteryVoltage = (char)(batteryLevelInt&0x3fff);
+            cur.numReadInts += 1;
             if (DEBUG) Slog.i(TAG, "READ DELTA: batteryToken=0x"
                     + Integer.toHexString(batteryLevelInt)
                     + " batteryLevel=" + cur.batteryLevel
@@ -1633,6 +1669,7 @@
             cur.batteryStatus = (byte)((stateInt>>28)&0xf);
             cur.batteryHealth = (byte)((stateInt>>24)&0xf);
             cur.batteryPlugType = (byte)((stateInt>>22)&0x3);
+            cur.numReadInts += 1;
             if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"
                     + Integer.toHexString(stateInt)
                     + " batteryStatus=" + cur.batteryStatus
@@ -1643,55 +1680,78 @@
             cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~DELTA_STATE_MASK));
         }
 
+        if ((firstToken&DELTA_WAKELOCK_FLAG) != 0) {
+            cur.wakelockTag = cur.localWakelockTag;
+            int index = src.readInt();
+            readHistoryTag(index, cur.wakelockTag);
+            cur.numReadInts += 1;
+            if (DEBUG) Slog.i(TAG, "READ DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx
+                + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
+        } else {
+            cur.wakelockTag = null;
+        }
+
         if (cur.cmd == HistoryItem.CMD_EVENT) {
-            int codeAndIndex = src.readInt();
+            cur.eventTag = cur.localEventTag;
+            final int codeAndIndex = src.readInt();
             cur.eventCode = (codeAndIndex&0xffff);
-            int index = ((codeAndIndex>>16)&0xffff);
-            cur.eventName = mReadHistoryStrings[index];
-            cur.eventNameIdx = index;
-            cur.eventUid = src.readInt();
+            final int index = ((codeAndIndex>>16)&0xffff);
+            readHistoryTag(index, cur.eventTag);
+            cur.numReadInts += 1;
+            if (DEBUG) Slog.i(TAG, "READ DELTA: event=" + cur.eventCode + " tag=#"
+                    + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
+                    + cur.eventTag.string);
         } else {
             cur.eventCode = HistoryItem.EVENT_NONE;
         }
     }
 
-    int mChangedBufferStates = 0;
-
     void addHistoryBufferLocked(long curTime) {
         if (!mHaveBatteryLevel || !mRecordingHistory) {
             return;
         }
 
         final long timeDiff = (mHistoryBaseTime+curTime) - mHistoryLastWritten.time;
+        final int diffStates = mHistoryLastWritten.states^mHistoryCur.states;
+        final int lastDiffStates = mHistoryLastWritten.states^mHistoryLastLastWritten.states;
+        if (DEBUG) Slog.i(TAG, "ADD: tdelta=" + timeDiff + " diff="
+                + Integer.toHexString(diffStates) + " lastDiff="
+                + Integer.toHexString(lastDiffStates));
         if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
-                && timeDiff < 2000
-                && ((mHistoryLastWritten.states^mHistoryCur.states)&mChangedBufferStates) == 0) {
-            // If the current is the same as the one before, then we no
-            // longer need the entry.
+                && timeDiff < 1000 && (diffStates&lastDiffStates) == 0
+                && (mHistoryLastWritten.wakelockTag == null || mHistoryCur.wakelockTag == null)
+                && mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel
+                && mHistoryLastWritten.batteryStatus == mHistoryCur.batteryStatus
+                && mHistoryLastWritten.batteryHealth == mHistoryCur.batteryHealth
+                && mHistoryLastWritten.batteryPlugType == mHistoryCur.batteryPlugType
+                && mHistoryLastWritten.batteryTemperature == mHistoryCur.batteryTemperature
+                && mHistoryLastWritten.batteryVoltage == mHistoryCur.batteryVoltage) {
+            // We can merge this new change in with the last one.  Merging is
+            // allows as long as only the states have changed, and within those states
+            // as long as no bit has changed both between now and the last entry, as
+            // well as the last entry and the one before it (so we capture any toggles).
+            if (DEBUG) Slog.i(TAG, "ADD: rewinding back to " + mHistoryBufferLastPos);
             mHistoryBuffer.setDataSize(mHistoryBufferLastPos);
             mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);
             mHistoryBufferLastPos = -1;
-            if (mHistoryLastLastWritten.cmd == HistoryItem.CMD_UPDATE
-                    && timeDiff < 500 && mHistoryLastLastWritten.sameNonEvent(mHistoryCur)) {
-                // If this results in us returning to the state written
-                // prior to the last one, then we can just delete the last
-                // written one and drop the new one.  Nothing more to do.
-                mHistoryLastWritten.setTo(mHistoryLastLastWritten);
-                mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
-                return;
-            }
-            mChangedBufferStates |= mHistoryLastWritten.states^mHistoryCur.states;
             curTime = mHistoryLastWritten.time - mHistoryBaseTime;
+            // If the last written history had a wakelock tag, we need to retain it.
+            // Note that the condition above made sure that we aren't in a case where
+            // both it and the current history item have a wakelock tag.
+            if (mHistoryLastWritten.wakelockTag != null) {
+                mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+                mHistoryCur.wakelockTag.setTo(mHistoryLastWritten.wakelockTag);
+            }
             mHistoryLastWritten.setTo(mHistoryLastLastWritten);
-        } else {
-            mChangedBufferStates = 0;
         }
 
         final int dataSize = mHistoryBuffer.dataSize();
         if (dataSize >= MAX_HISTORY_BUFFER) {
             if (!mHistoryOverflow) {
                 mHistoryOverflow = true;
+                addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
                 addHistoryBufferLocked(curTime, HistoryItem.CMD_OVERFLOW);
+                return;
             }
 
             // Once we've reached the maximum number of items, we only
@@ -1704,6 +1764,9 @@
                                     & HistoryItem.MOST_INTERESTING_STATES) == 0)) {
                 return;
             }
+
+            addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
+            return;
         }
 
         addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
@@ -1719,10 +1782,8 @@
 
     private void addHistoryBufferLocked(long curTime, byte cmd,
             int eventCode, String eventName, int eventUid) {
-        int origPos = 0;
         if (mIteratingHistory) {
-            origPos = mHistoryBuffer.dataPosition();
-            mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
+            throw new IllegalStateException("Can't do this while iterating history!");
         }
         mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
         mHistoryLastLastWritten.setTo(mHistoryLastWritten);
@@ -1730,12 +1791,10 @@
                 eventCode, eventUid, eventName, mHistoryCur);
         writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
         mLastHistoryTime = curTime;
+        mHistoryCur.wakelockTag = null;
         if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
                 + " now " + mHistoryBuffer.dataPosition()
                 + " size is now " + mHistoryBuffer.dataSize());
-        if (mIteratingHistory) {
-            mHistoryBuffer.setDataPosition(origPos);
-        }
     }
 
     int mChangedStates = 0;
@@ -1845,11 +1904,12 @@
 
         mHistoryBuffer.setDataSize(0);
         mHistoryBuffer.setDataPosition(0);
-        mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER/2);
+        mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER / 2);
         mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
         mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
-        mHistoryStringPool.clear();
-        mNextHistoryStringIdx = 0;
+        mHistoryTagPool.clear();
+        mNextHistoryTagIdx = 0;
+        mNumHistoryTagChars = 0;
         mHistoryBufferLastPos = -1;
         mHistoryOverflow = false;
     }
@@ -1914,6 +1974,9 @@
                 mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
                         + Integer.toHexString(mHistoryCur.states));
+                mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+                mHistoryCur.wakelockTag.string = name;
+                mHistoryCur.wakelockTag.uid = uid;
                 addHistoryRecordLocked(SystemClock.elapsedRealtime());
             }
             mWakeLockNesting++;
@@ -2161,7 +2224,7 @@
 
             // Fake a wake lock, so we consider the device waked as long
             // as the screen is on.
-            noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
+            noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL);
             
             // Update discharge amounts.
             if (mOnBatteryInternal) {
@@ -4854,11 +4917,14 @@
     public boolean startIteratingOldHistoryLocked() {
         if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
                 + " pos=" + mHistoryBuffer.dataPosition());
+        if ((mHistoryIterator = mHistory) == null) {
+            return false;
+        }
         mHistoryBuffer.setDataPosition(0);
         mHistoryReadTmp.clear();
         mReadOverflow = false;
         mIteratingHistory = true;
-        return (mHistoryIterator = mHistory) != null;
+        return true;
     }
 
     @Override
@@ -4898,6 +4964,15 @@
     public void finishIteratingOldHistoryLocked() {
         mIteratingHistory = false;
         mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
+        mHistoryIterator = null;
+    }
+
+    public int getHistoryTotalSize() {
+        return MAX_HISTORY_BUFFER;
+    }
+
+    public int getHistoryUsedSize() {
+        return mHistoryBuffer.dataSize();
     }
 
     @Override
@@ -4907,9 +4982,15 @@
         mHistoryBuffer.setDataPosition(0);
         mReadOverflow = false;
         mIteratingHistory = true;
-        mReadHistoryStrings = new String[mHistoryStringPool.size()];
-        for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) {
-            mReadHistoryStrings[ent.getValue()] = ent.getKey();
+        mReadHistoryStrings = new String[mHistoryTagPool.size()];
+        mReadHistoryUids = new int[mHistoryTagPool.size()];
+        mReadHistoryChars = 0;
+        for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
+            final HistoryTag tag = ent.getKey();
+            final int idx = ent.getValue();
+            mReadHistoryStrings[idx] = tag.string;
+            mReadHistoryUids[idx] = tag.uid;
+            mReadHistoryChars += tag.string.length() + 1;
         }
         return mHistoryBuffer.dataSize() > 0;
     }
@@ -4920,11 +5001,23 @@
     }
 
     @Override
-    public String getHistoryStringPoolItem(int index) {
+    public int getHistoryStringPoolBytes() {
+        // Each entry is a fixed 12 bytes: 4 for index, 4 for uid, 4 for string size
+        // Each string character is 2 bytes.
+        return (mReadHistoryStrings.length * 12) + (mReadHistoryChars * 2);
+    }
+
+    @Override
+    public String getHistoryTagPoolString(int index) {
         return mReadHistoryStrings[index];
     }
 
     @Override
+    public int getHistoryTagPoolUid(int index) {
+        return mReadHistoryUids[index];
+    }
+
+    @Override
     public boolean getNextHistoryLocked(HistoryItem out) {
         final int pos = mHistoryBuffer.dataPosition();
         if (pos == 0) {
@@ -5717,17 +5810,24 @@
 
         mHistoryBuffer.setDataSize(0);
         mHistoryBuffer.setDataPosition(0);
-        mHistoryStringPool.clear();
-        mNextHistoryStringIdx = 0;
+        mHistoryTagPool.clear();
+        mNextHistoryTagIdx = 0;
+        mNumHistoryTagChars = 0;
 
-        int numStrings = in.readInt();
-        for (int i=0; i<numStrings; i++) {
-            String str = in.readString();
+        int numTags = in.readInt();
+        for (int i=0; i<numTags; i++) {
             int idx = in.readInt();
-            mHistoryStringPool.put(str, idx);
-            if (idx >= mNextHistoryStringIdx) {
-                mNextHistoryStringIdx = idx+1;
+            String str = in.readString();
+            int uid = in.readInt();
+            HistoryTag tag = new HistoryTag();
+            tag.string = str;
+            tag.uid = uid;
+            tag.poolIdx = idx;
+            mHistoryTagPool.put(tag, idx);
+            if (idx >= mNextHistoryTagIdx) {
+                mNextHistoryTagIdx = idx+1;
             }
+            mNumHistoryTagChars += tag.string.length() + 1;
         }
 
         int bufSize = in.readInt();
@@ -5797,10 +5897,12 @@
             Slog.i(TAG, sb.toString());
         }
         out.writeLong(mHistoryBaseTime + mLastHistoryTime);
-        out.writeInt(mHistoryStringPool.size());
-        for (HashMap.Entry<String, Integer> ent : mHistoryStringPool.entrySet()) {
-            out.writeString(ent.getKey());
+        out.writeInt(mHistoryTagPool.size());
+        for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
+            HistoryTag tag = ent.getKey();
             out.writeInt(ent.getValue());
+            out.writeString(tag.string);
+            out.writeInt(tag.uid);
         }
         out.writeInt(mHistoryBuffer.dataSize());
         if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index 7ca6c1b..ed676bb 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -163,7 +163,7 @@
 
     public MenuItem setIcon(int iconRes) {
         mIconResId = iconRes;
-        mIconDrawable = mContext.getResources().getDrawable(iconRes);
+        mIconDrawable = mContext.getDrawable(iconRes);
         return this;
     }
 
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index b7cb0de..b776226 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -1121,7 +1121,7 @@
             }
             
             if (iconRes > 0) {
-                mHeaderIcon = r.getDrawable(iconRes);
+                mHeaderIcon = getContext().getDrawable(iconRes);
             } else if (icon != null) {
                 mHeaderIcon = icon;
             }
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 4d0a326..61dcaca 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -385,7 +385,7 @@
         }
 
         if (mIconResId != NO_ICON) {
-            Drawable icon =  mMenu.getResources().getDrawable(mIconResId);
+            Drawable icon =  mMenu.getContext().getDrawable(mIconResId);
             mIconResId = NO_ICON;
             mIconDrawable = icon;
             return icon;
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index ff2c625..1273c4d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -697,7 +697,7 @@
     }
 
     public void setIcon(int resId) {
-        setIcon(resId != 0 ? mContext.getResources().getDrawable(resId) : null);
+        setIcon(resId != 0 ? mContext.getDrawable(resId) : null);
     }
 
     public boolean hasIcon() {
@@ -712,7 +712,7 @@
     }
 
     public void setLogo(int resId) {
-        setLogo(resId != 0 ? mContext.getResources().getDrawable(resId) : null);
+        setLogo(resId != 0 ? mContext.getDrawable(resId) : null);
     }
 
     public boolean hasLogo() {
@@ -1417,7 +1417,7 @@
 
         public void setUpIndicator(int resId) {
             mUpIndicatorRes = resId;
-            mUpView.setImageDrawable(resId != 0 ? getResources().getDrawable(resId) : null);
+            mUpView.setImageDrawable(resId != 0 ? getContext().getDrawable(resId) : null);
         }
 
         @Override
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboard.java b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
index 8368136..7483e75 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboard.java
@@ -72,8 +72,8 @@
 
     private void init(Context context) {
         final Resources res = context.getResources();
-        mShiftIcon = res.getDrawable(R.drawable.sym_keyboard_shift);
-        mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked);
+        mShiftIcon = context.getDrawable(R.drawable.sym_keyboard_shift);
+        mShiftLockIcon = context.getDrawable(R.drawable.sym_keyboard_shift_locked);
         sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
                 R.dimen.password_keyboard_spacebar_vertical_correction);
     }
diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
index cd1ccd3..93ea5b3 100644
--- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
@@ -234,7 +234,7 @@
         mMagneticTargets = a.getBoolean(R.styleable.GlowPadView_magneticTargets, mMagneticTargets);
 
         int pointId = getResourceId(a, R.styleable.GlowPadView_pointDrawable);
-        Drawable pointDrawable = pointId != 0 ? res.getDrawable(pointId) : null;
+        Drawable pointDrawable = pointId != 0 ? context.getDrawable(pointId) : null;
         mGlowRadius = a.getDimension(R.styleable.GlowPadView_glowRadius, 0.0f);
 
         TypedValue outValue = new TypedValue();
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 3116955..5d49204 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -141,7 +141,8 @@
     *needsDetach = false;
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     if (env == NULL) {
-        JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
+        JavaVMAttachArgs args = {
+            JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL };
         JavaVM* vm = AndroidRuntime::getJavaVM();
         int result = vm->AttachCurrentThread(&env, (void*) &args);
         if (result != JNI_OK) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b7a06b5..7ea08af 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -583,7 +583,7 @@
     <!-- =============================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that provide access to the user voicemail box. -->
+    <!-- Used for permissions that provide access to device alarms. -->
     <permission-group android:name="android.permission-group.DEVICE_ALARMS"
         android:label="@string/permgrouplab_deviceAlarms"
         android:icon="@drawable/perm_group_device_alarms"
@@ -1061,7 +1061,7 @@
     <!-- =========================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that are associated with accessing and modifyign
+    <!-- Used for permissions that are associated with accessing and modifying
          telephony state: placing calls, intercepting outgoing calls, reading
          and modifying the phone state. -->
     <permission-group android:name="android.permission-group.PHONE_CALLS"
@@ -1727,6 +1727,13 @@
         android:label="@string/permlab_recovery"
         android:description="@string/permdesc_recovery" />
 
+    <!-- Allows the system to bind to an application's idle services
+         @hide -->
+    <permission android:name="android.permission.BIND_IDLE_SERVICE"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_bindIdleService"
+        android:description="@string/permdesc_bindIdleService" />
+
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
     <!-- ========================================= -->
@@ -2728,6 +2735,14 @@
             </intent-filter>
         </service>
 
+        <service android:name="com.android.server.MountServiceIdler"
+                 android:exported="false"
+                 android:permission="android.permission.BIND_IDLE_SERVICE" >
+            <intent-filter>
+                <action android:name="android.service.idle.IdleService" />
+            </intent-filter>
+        </service>
+
     </application>
 
 </manifest>
diff --git a/core/res/res/drawable-hdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-hdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..8d529b8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_search_api_holo_light.png b/core/res/res/drawable-hdpi/ic_search_api_holo_light.png
index 72e207b..8b15ecb 100644
--- a/core/res/res/drawable-hdpi/ic_search_api_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..32062a6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png
index 3481c98..d2b2d21 100644
--- a/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search.png b/core/res/res/drawable-mdpi/ic_search.png
index 4be72f1..66145e0 100644
--- a/core/res/res/drawable-mdpi/ic_search.png
+++ b/core/res/res/drawable-mdpi/ic_search.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-mdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..4771a56
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search_api_holo_light.png b/core/res/res/drawable-mdpi/ic_search_api_holo_light.png
index f2e26f8..60a55f8 100644
--- a/core/res/res/drawable-mdpi/ic_search_api_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search.png b/core/res/res/drawable-mdpi/ic_voice_search.png
index 73c6be6..b2535fb 100644
--- a/core/res/res/drawable-mdpi/ic_voice_search.png
+++ b/core/res/res/drawable-mdpi/ic_voice_search.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..fcc2105
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png
index 71d838e..b516b95 100644
--- a/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search.png b/core/res/res/drawable-xhdpi/ic_search.png
index 998f91b..738a392 100644
--- a/core/res/res/drawable-xhdpi/ic_search.png
+++ b/core/res/res/drawable-xhdpi/ic_search.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-xhdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..b0d7acf
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png b/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png
index a4cdf1c..c9626a0 100644
--- a/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_category_default.png b/core/res/res/drawable-xhdpi/ic_search_category_default.png
index 7d5170e..351cfe0 100644
--- a/core/res/res/drawable-xhdpi/ic_search_category_default.png
+++ b/core/res/res/drawable-xhdpi/ic_search_category_default.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search.png b/core/res/res/drawable-xhdpi/ic_voice_search.png
index c625a36..3f0518b 100644
--- a/core/res/res/drawable-xhdpi/ic_voice_search.png
+++ b/core/res/res/drawable-xhdpi/ic_voice_search.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..eb6e5fa
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png
index c332ba0..c6b40bb 100644
--- a/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_search_api_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_search_api_holo_dark.png
new file mode 100644
index 0000000..eb30465
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_search_api_holo_light.png b/core/res/res/drawable-xxhdpi/ic_search_api_holo_light.png
new file mode 100644
index 0000000..bc14415
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_dark.png
new file mode 100644
index 0000000..813048c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_light.png b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_light.png
new file mode 100644
index 0000000..8addde0
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_voice_search_api_holo_light.png
Binary files differ
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0643e3b..8eadf2c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1526,7 +1526,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"S\'està desbloquejant la targeta SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Codi PIN incorrecte."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Escriu un PIN que tingui de 4 a 8 números."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"El codi PUK ha de contenir 8 números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"El codi PUK ha de tenir 8 números."</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Torna a introduir el codi PUK correcte. Els intents repetits faran que es desactivi la SIM de manera permanent."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Els codis PIN no coincideixen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Massa intents incorrectes"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 85efbf6..1a5228d 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1526,8 +1526,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ապակողպում է SIM քարտը ..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Սխալ PIN ծածկագիր:"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Մուտքագրեք PIN, որը 4-ից 8 թիվ է:"</string>
-    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
-    <skip />
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK կոդը պետք է լինի 8 թիվ:"</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Վերամուտքագրեք ճիշտ PUK ծածկագիրը: Կրկնվող փորձերը ընդմիշտ կկասեցնեն SIM քարտը:"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN ծածկագրերը չեն համընկնում"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Չափից շատ սխեմայի փորձեր"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index eb03857..38d518a 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1200,7 +1200,7 @@
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"មិន​​អាច​តភ្ជាប់​វ៉ាយហ្វាយ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត​មិន​ល្អ។"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"វ៉ាយហ្វាយ​ផ្ទាល់"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ចាប់ផ្ដើម​វ៉ាយហ្វាយ​ដោយ​ផ្ទាល់។ វា​នឹង​បិទ​វ៉ាយហ្វាយ ។"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ចាប់ផ្ដើម​វ៉ាយហ្វាយ​ផ្ទាល់។ វា​នឹង​បិទ​វ៉ាយហ្វាយ​ហតស្ពត។"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"មិន​អាច​ចាប់ផ្ដើម​វ៉ាយហ្វា​ដោយ​ផ្ទាល់។"</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"បើក​​វ៉ាយហ្វាយ​ផ្ទាល់"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"ប៉ះ​ ដើម្បី​កំណត់"</string>
@@ -1357,7 +1357,7 @@
     <string name="submit" msgid="1602335572089911941">"ដាក់​ស្នើ"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"បាន​បើក​របៀប​រថយន្ត"</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"ប៉ះ​ ដើម្បី​ចេញ​ពី​របៀប​រថយន្ត​។"</string>
-    <string name="tethered_notification_title" msgid="3146694234398202601">"​ភ្ជាប់ ឬ​ hotspot សកម្ម"</string>
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម"</string>
     <string name="tethered_notification_message" msgid="6857031760103062982">"ប៉ះ​ ដើម្បី​រៀបចំ។"</string>
     <string name="back_button_label" msgid="2300470004503343439">"ថយក្រោយ"</string>
     <string name="next_button_label" msgid="1080555104677992408">"បន្ទាប់"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 62cdcaf..f9d005d 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1526,8 +1526,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kad SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kod PIN salah."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
-    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
-    <skip />
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Kod PUK mestilah 8 nombor."</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 4d6f459..b222103 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1526,8 +1526,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Cod PIN incorect."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN format din 4 până la 8 cifre."</string>
-    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
-    <skip />
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Codul PUK trebuie să conțină 8 numere."</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 01e1255..d0fcc09 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1526,7 +1526,7 @@
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Inafungua SIM kadi..."</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Msimbo wa PIN usio sahihi."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Charaza PIN iliyo na tarakimu kati ya 4 na 8."</string>
-    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Msimbo wa PUK lazima uwe na nambari 8."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Msimbo wa PUK lazima uwe na tarakimu 8."</string>
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ingiza upya msimbo sahihi wa PUK. Majaribio yanayorudiwa yatalemaza SIM kabisa."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Misimbo ya PIN haifanani"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Majaribio mengi mno ya mchoro"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ca9c8bd..9526e13 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2244,6 +2244,17 @@
              Hence, the TextView is a label for the EditText. -->
         <attr name="labelFor" format="integer" />
 
+        <!-- Specifies a theme override for a view. When a theme override is set, the
+             view will be inflated using a {@link android.content.Context} themed with
+             the specified resource. During XML inflation, any child views under the
+             view with a theme override will inherit the themed context. -->
+        <attr name="theme" />
+
+        <!-- Specifies that the shared name of the View to be shared with another Activity.
+             When transitioning between Activities, the name links a UI element in the starting
+             Activity to UI element in the called Activity. Names should be unique in the
+             View hierarchy. -->
+        <attr name="sharedElementName" format="string" />
     </declare-styleable>
 
     <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
@@ -2330,6 +2341,14 @@
             <!-- Use the children's optical bounds when laying out this container. -->
             <enum name="opticalBounds" value="1" />
         </attr>
+
+        <!-- Sets whether or not this ViewGroup should be treated as a single entity
+             when doing an Activity transition. Typically, the elements inside a
+             ViewGroup are each transitioned from the scene individually. The default
+             for a ViewGroup is false unless it has a background.
+             See {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)}
+             for more information. -->
+        <attr name="transitionGroup" format="boolean" />
     </declare-styleable>
 
     <!-- A {@link android.view.ViewStub} lets you lazily include other XML layouts
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 5c0baaa..56bb15f 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -82,4 +82,5 @@
   <item type="id" name="action_bar_spinner" />
   <item type="id" name="current_scene" />
   <item type="id" name="scene_layoutid_cache" />
+  <item type="id" name="shared_element_name" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e99b5ba..722f965 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2104,6 +2104,12 @@
   <public type="attr" name="controlY1" />
   <public type="attr" name="controlX2" />
   <public type="attr" name="controlY2" />
+  <public type="attr" name="fromSceneName" />
+  <public type="attr" name="toSceneName" />
+  <public type="attr" name="sharedElementName" />
+  <public type="attr" name="transitionGroup" />
+
+  <public type="id" name="shared_element_name" />
 
   <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
   <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 785e788..ee68199 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1176,6 +1176,11 @@
     <string name="permdesc_manageCaCertificates">Allows the app to install and uninstall CA certificates as trusted credentials.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindIdleService">bind to idle services</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindIdleService">Allows the app to interact with application-defined idle services.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_diagnostic">read/write to resources owned by diag</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_diagnostic">Allows the app to read and write to
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 76fbded..7a654e6 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -363,7 +363,7 @@
         <item name="searchViewTextField">@drawable/textfield_searchview_holo_dark</item>
         <item name="searchViewTextFieldRight">@drawable/textfield_searchview_right_holo_dark</item>
         <item name="searchViewCloseIcon">@android:drawable/ic_clear</item>
-        <item name="searchViewSearchIcon">@android:drawable/ic_search</item>
+        <item name="searchViewSearchIcon">@android:drawable/ic_search_api_holo_dark</item>
         <item name="searchViewGoIcon">@android:drawable/ic_go</item>
         <item name="searchViewVoiceIcon">@android:drawable/ic_voice_search</item>
         <item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_holo_dark</item>
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 7b9b3fb..bcd4607 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -61,7 +61,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on January 8, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on February 4, 2014.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -92,7 +92,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on January 8, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on February 4, 2014.
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
@@ -133,17 +133,17 @@
 </tr>
 <tr>
 <td>2.0</th>
-<td>93.5%</td>
+<td>92.3%</td>
 </tr>
 <tr>
 <td>3.0</th>
-<td>6.4%</td>
+<td>7.6%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on January 8, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on February 4, 2014</em></p>
 
 
 
@@ -161,7 +161,7 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chf=bg%2Cs%2C00000000&chd=t%3A1.3%2C21.2%2C0.1%2C16.9%2C59.1%2C1.4&chco=c4df9b%2C6fad0c&chs=500x250&cht=p",
+    "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chf=bg%2Cs%2C00000000&chd=t%3A1.3%2C20.0%2C0.1%2C16.1%2C60.7%2C1.8&chco=c4df9b%2C6fad0c",
     "data": [
       {
         "api": 8,
@@ -171,7 +171,7 @@
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "21.2"
+        "perc": "20.0"
       },
       {
         "api": 13,
@@ -181,27 +181,27 @@
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "16.9"
+        "perc": "16.1"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "35.9"
+        "perc": "35.5"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "15.4"
+        "perc": "16.3"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "7.8"
+        "perc": "8.9"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "1.4"
+        "perc": "1.8"
       }
     ]
   }
@@ -217,30 +217,30 @@
     "data": {
       "Large": {
         "hdpi": "0.6",
-        "ldpi": "0.9",
-        "mdpi": "4.5",
-        "tvdpi": "1.7",
-        "xhdpi": "0.7"
+        "ldpi": "0.8",
+        "mdpi": "4.4",
+        "tvdpi": "1.6",
+        "xhdpi": "0.6"
       },
       "Normal": {
-        "hdpi": "33.0",
+        "hdpi": "33.3",
         "ldpi": "0.1",
-        "mdpi": "14.2",
-        "xhdpi": "20.1",
-        "xxhdpi": "10.6"
+        "mdpi": "13.9",
+        "xhdpi": "20.2",
+        "xxhdpi": "11.3"
       },
       "Small": {
-        "ldpi": "8.2"
+        "ldpi": "8.1"
       },
       "Xlarge": {
-        "hdpi": "0.4",
+        "hdpi": "0.3",
         "ldpi": "0.1",
-        "mdpi": "4.7",
+        "mdpi": "4.5",
         "xhdpi": "0.2"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chf=bg%2Cs%2C00000000&chd=t%3A9.4%2C23.5%2C1.7%2C34.0%2C21.0%2C10.6&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
-    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chf=bg%2Cs%2C00000000&chd=t%3A5.4%2C8.5%2C78.0%2C8.2&chco=c4df9b%2C6fad0c&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%3A9.1%2C22.8%2C1.6%2C34.3%2C21.0%2C11.3&chco=c4df9b%2C6fad0c",
+    "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=Xlarge%7CLarge%7CNormal%7CSmall&chf=bg%2Cs%2C00000000&chd=t%3A5.1%2C8.0%2C78.9%2C8.1&chco=c4df9b%2C6fad0c"
   }
 ];
 
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index bf7fbe2..fb5daf8 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -92,7 +92,10 @@
 <p><b>Using Android Studio:</b></p>
 
 <ol>
-  <li>Open the <code>build.gradle</code> file inside your application directory.</li>
+  <li>Open the <code>build.gradle</code> file inside your application module directory. 
+      <p class="note"><strong>Note:</strong> Android Studio projects contain a top-level 
+      <code>build.gradle</code> file and a <code>build.gradle</code> file for each module. 
+      Be sure to edit the file for your application module.</p></li>
   <li>Add a new build rule under <code>dependencies</code> for the latest version of
 <code>play-services</code>. For example:
 <pre class="no-pretty-print">
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index c62510b..297a2dc 100644
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -56,7 +56,9 @@
 RenderScript kernel language used in this script. Currently, 1 is the only valid value.</li>
 
 <li>A pragma declaration (<code>#pragma rs java_package_name(com.example.app)</code>) that
-declares the package name of the Java classes reflected from this script.</li>
+declares the package name of the Java classes reflected from this script.
+Note that your .rs file must be part of your application package, and not in a
+library project.</li>
 
 <li>Some number of invokable functions. An invokable function is a single-threaded RenderScript
 function that you can call from your Java code with arbitrary arguments. These are often useful for
@@ -308,4 +310,4 @@
 <li><strong>Tear down the RenderScript context.</strong> The RenderScript context can be destroyed
 with {@link android.renderscript.RenderScript#destroy} or by allowing the RenderScript context
 object to be garbage collected. This will cause any further use of any object belonging to that
-context to throw an exception.</li> </ol>
\ No newline at end of file
+context to throw an exception.</li> </ol>
diff --git a/docs/html/tools/help/adb.jd b/docs/html/tools/help/adb.jd
index 1850123..f980042 100644
--- a/docs/html/tools/help/adb.jd
+++ b/docs/html/tools/help/adb.jd
@@ -27,6 +27,7 @@
   </li>
   <li><a href="#logcat">Enabling logcat logging</a></li>
   <li><a href="#stopping">Stopping the adb server</a></li>
+  <li><a href="#wireless">Wireless usage</a></li>
 </ol>
 
 </div>
@@ -1342,3 +1343,100 @@
 You can then restart the server by issuing any other adb command. </p>
 
 
+<h2 id="wireless">Wireless usage</h2>
+
+<p>
+adb is usually used over USB.  However, it is also possible to use over
+Wi-Fi, as described here.
+</p>
+
+<ol>
+
+<li>
+Connect Android device and adb host computer
+to a common Wi-Fi network accessible to both.
+We have found that not all access points
+are suitable; you may need to use an access point
+whose firewall is configured properly to support adb.
+</li>
+
+<li>
+Connect the device with USB cable to host.
+</li>
+
+<li>
+Make sure adb is running in USB mode on host.
+<pre>
+$ adb usb
+restarting in USB mode
+</pre>
+</li>
+
+<li>
+Connect to the device over USB.
+<pre>
+$ adb devices
+List of devices attached
+######## device
+</pre>
+</li>
+
+<li>
+Restart host adb in tcpip mode.
+<pre>
+$ adb tcpip 5555
+restarting in TCP mode port: 5555
+</pre>
+</li>
+
+<li>
+Find out the IP address of the Android device:
+Settings -> About tablet -> Status -> IP address.
+Remember the IP address, of the form <code>#.#.#.#</code>.
+</li>
+
+<li>
+Connect adb host to device:
+<pre>
+$ adb connect #.#.#.#
+connected to #.#.#.#:5555
+</pre>
+</li>
+
+<li>
+Remove USB cable from device, and confirm you can still access device:
+<pre>
+$ adb devices
+List of devices attached
+#.#.#.#:5555 device
+</pre>
+
+</ol>
+
+<p>
+You're now good to go!
+</p>
+
+<p>
+If the adb connection is ever lost:
+</p>
+
+<ol>
+
+<li>
+Make sure that your host is still connected to the same Wi-Fi network your Android device is.
+</li>
+
+<li>
+Reconnect by executing the "adb connect" step again.
+</li>
+
+<li>
+Or if that doesn't work, reset your adb host:
+<pre>
+adb kill-server
+</pre>
+and then start over from the beginning.
+</li>
+
+</ol>
diff --git a/docs/html/tools/samples/index.jd b/docs/html/tools/samples/index.jd
deleted file mode 100644
index a0d11e9..0000000
--- a/docs/html/tools/samples/index.jd
+++ /dev/null
@@ -1,32 +0,0 @@
-page.title=Samples
-page.tags=example,code
-@jd:body
-
-<p>To help you understand some fundamental Android APIs and coding practices, a variety of sample
-code is available from the Android SDK Manager. Each version of the Android platform available
-from the SDK Manager offers its own set of sample apps.</p>
-
-<p>To download the samples:</p>
-<ol>
-  <li>Launch the Android SDK Manager.
-    <ul>
-      <li>On Windows, double-click the SDK Manager.exe file at the root of the Android SDK
-directory.</li>
-      <li>On Mac or Linux, open a terminal to the {@code tools/} directory in the
-Android SDK, then execute {@code android sdk}.</ul>
-  </li>
-  <li>Expand the list of packages for the latest Android platform.</li>
-  <li>Select and download <em>Samples for SDK</em>.</li>
-</ol>
-
-<p>When the download is complete, you can find the source code for all samples at this location:</p>
-
-<p style="margin-left:2em">
-<code>&lt;sdk&gt;/samples/android-&lt;version>/</code>
-</p>
-
-<p>The {@code &lt;version>} number corresponds to the platform's
-  <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level</a>.</p>
-
-<p>You can easily create new Android projects with the downloaded samples, modify them
-if you'd like, and then run them on an emulator or device.</p>
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 3e6b6d4..a8424e6 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -240,12 +240,6 @@
 
 
   <li class="nav-section">
-    <div class="nav-section-header empty"><a href="<?cs var:toroot
-?>tools/samples/index.html"><span class="en">Samples</span></a></div>
-  </li>
-
-
-  <li class="nav-section">
     <div class="nav-section-header">
     <a href="<?cs var:toroot ?>tools/adk/index.html">
       <span class="en">ADK</span></a>
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 52e5b5b..9360558 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -456,7 +456,7 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    public void draw(Canvas canvas) {
         Bitmap bitmap = mBitmap;
         if (bitmap != null) {
             final BitmapState state = mBitmapState;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 2ec4284..b8365aa 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -39,9 +39,6 @@
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
-import android.view.DisplayList;
-import android.view.HardwareCanvas;
-import android.view.HardwareRenderer;
 import android.view.View;
 
 import java.io.IOException;
@@ -142,96 +139,16 @@
     private Rect mBounds = ZERO_BOUNDS_RECT;  // lazily becomes a new Rect()
     private WeakReference<Callback> mCallback = null;
     private boolean mVisible = true;
-    private DisplayList mDisplayList;
 
     private int mLayoutDirection;
 
     /**
      * Draw in its bounds (set via setBounds) respecting optional effects such
      * as alpha (set via setAlpha) and color filter (set via setColorFilter).
-     * <p>
-     * Overriding this method will prevent caching optimizations. To enable
-     * optimizations, override {@link #onDraw} instead.
      *
      * @param canvas The canvas to draw into
      */
-    public void draw(Canvas canvas) {
-        if (canvas != null && canvas.isHardwareAccelerated() && false) { // temporarily disabled
-            final HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
-            final DisplayList displayList = getDisplayList(hardwareCanvas);
-            if (displayList != null) {
-                final int restoreCount = hardwareCanvas.save(Canvas.MATRIX_SAVE_FLAG);
-                hardwareCanvas.translate(mBounds.left, mBounds.top);
-                hardwareCanvas.drawDisplayList(displayList);
-                hardwareCanvas.restoreToCount(restoreCount);
-                return;
-            }
-        }
-
-        onDraw(canvas);
-    }
-
-    /**
-     * Draw in its bounds (set via setBounds) respecting optional effects such
-     * as alpha (set via setAlpha) and color filter (set via setColorFilter).
-     * <p>
-     * Overriding this method, rather than {@link #draw}, enables caching
-     * optimizations that avoid re-drawing when unnecessary.
-     *
-     * @param canvas The canvas to draw into
-     */
-    protected void onDraw(Canvas canvas) {
-        throw new UnsupportedOperationException(
-                "Drawable subclasses must implement either draw or onDraw");
-    }
-
-    /**
-     * Gets a display list that can be used to draw this drawable again without
-     * invoking its draw method.
-     *
-     * @param hardwareCanvas The hardware canvas.
-     * @return A DisplayList ready to replay, or null if caching is not enabled.
-     * @hide
-     */
-    private DisplayList getDisplayList(HardwareCanvas hardwareCanvas) {
-        DisplayList displayList = mDisplayList;
-        if (displayList != null && displayList.isValid()) {
-            // Note: This code assumes that the display list previously generated
-            // is compatible with the given hardware canvas.  That might not be true
-            // if we start using multiple different types of hardware canvas
-            // in the system someday.
-            return displayList;
-        }
-
-        displayList = DisplayList.create(getClass().getName());
-        mDisplayList = displayList;
-
-        final Rect bounds = mBounds;
-        final int width = bounds.width();
-        final int height = bounds.height();
-        final HardwareCanvas canvas = displayList.start(width, height);
-        canvas.onPreDraw(null);
-
-        // Draw the display list with origin (0,0) so that if the position
-        // changes then we can translate without recreating the display list.
-        final int restoreCount = canvas.save();
-        try {
-            canvas.translate(-bounds.left, -bounds.top);
-            onDraw(canvas);
-        } finally {
-            canvas.restoreToCount(restoreCount);
-            canvas.onPostDraw();
-            displayList.end();
-        }
-
-        displayList.setLeftTopRightBottom(0, 0, width, height);
-        displayList.setClipToBounds(false);
-        return displayList;
-    }
-
-    private void invalidateDisplayList() {
-        mDisplayList = null;
-    }
+    public abstract void draw(Canvas canvas);
 
     /**
      * Specify a bounding rectangle for the Drawable. This is where the drawable
@@ -246,11 +163,10 @@
 
         if (oldBounds.left != left || oldBounds.top != top ||
                 oldBounds.right != right || oldBounds.bottom != bottom) {
-            if (oldBounds.right - oldBounds.left != right - left
-                    || oldBounds.bottom - oldBounds.top != bottom - top) {
-                invalidateDisplayList();
+            if (!oldBounds.isEmpty()) {
+                // first invalidate the previous bounds
+                invalidateSelf();
             }
-
             mBounds.set(left, top, right, bottom);
             onBoundsChange(mBounds);
         }
@@ -438,8 +354,6 @@
      * @see #setCallback(android.graphics.drawable.Drawable.Callback) 
      */
     public void invalidateSelf() {
-        invalidateDisplayList();
-
         final Callback callback = getCallback();
         if (callback != null) {
             callback.invalidateDrawable(this);
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 6a9454c..e654db1 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -266,7 +266,7 @@
      * @see #setStroke(int, int) 
      */
     public void setStroke(int width, int color, float dashWidth, float dashGap) {
-        mGradientState.setStroke(width, color, dashWidth, dashGap);
+        mGradientState.setStroke(width, ColorStateList.valueOf(color), dashWidth, dashGap);
         setStrokeInternal(width, color, dashWidth, dashGap);
     }
 
@@ -288,15 +288,15 @@
      */
     public void setStroke(
             int width, ColorStateList colorStateList, float dashWidth, float dashGap) {
+        mGradientState.setStroke(width, colorStateList, dashWidth, dashGap);
+        final int color;
         if (colorStateList == null) {
-            setStroke(width, Color.TRANSPARENT, dashWidth, dashGap);
+            color = Color.TRANSPARENT;
         } else {
-            mGradientState.setStroke(width, colorStateList, dashWidth, dashGap);
-
             final int[] stateSet = getState();
-            final int color = colorStateList.getColorForState(stateSet, 0);
-            setStrokeInternal(width, color, dashWidth, dashGap);
+            color = colorStateList.getColorForState(stateSet, 0);
         }
+        setStrokeInternal(width, color, dashWidth, dashGap);
     }
 
     private void setStrokeInternal(int width, int color, float dashWidth, float dashGap) {
@@ -472,7 +472,7 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    public void draw(Canvas canvas) {
         if (!ensureValidRect()) {
             // nothing to draw
             return;
@@ -529,8 +529,7 @@
             mFillPaint.setAlpha(currFillAlpha);
             mFillPaint.setDither(mDither);
             mFillPaint.setColorFilter(mColorFilter);
-            if (mColorFilter != null && !mGradientState.mHasSolidColor
-                    && mGradientState.mColorStateList == null) {
+            if (mColorFilter != null && mGradientState.mColorStateList == null) {
                 mFillPaint.setColor(mAlpha << 24);
             }
             if (haveStroke) {
@@ -672,7 +671,7 @@
      * @see #setColors(int[]) 
      */
     public void setColor(int argb) {
-        mGradientState.setSolidColor(argb);
+        mGradientState.setColorStateList(ColorStateList.valueOf(argb));
         mFillPaint.setColor(argb);
         invalidateSelf();
     }
@@ -691,14 +690,16 @@
      * @see #mutate()
      */
     public void setColor(ColorStateList colorStateList) {
+        mGradientState.setColorStateList(colorStateList);
+        final int color;
         if (colorStateList == null) {
-            setColor(Color.TRANSPARENT);
+            color = Color.TRANSPARENT;
         } else {
-            final int color = colorStateList.getColorForState(getState(), 0);
-            mGradientState.setColorStateList(colorStateList);
-            mFillPaint.setColor(color);
-            invalidateSelf();
+            final int[] stateSet = getState();
+            color = colorStateList.getColorForState(stateSet, 0);
         }
+        mFillPaint.setColor(color);
+        invalidateSelf();
     }
 
     @Override
@@ -910,7 +911,7 @@
 
                 // If we don't have a solid color, the alpha channel must be
                 // maxed out so that alpha modulation works correctly.
-                if (!st.mHasSolidColor && st.mColorStateList == null) {
+                if (st.mColorStateList == null) {
                     mFillPaint.setColor(Color.BLACK);
                 }
             }
@@ -1202,10 +1203,7 @@
         public int[] mTempColors; // no need to copy
         public float[] mTempPositions; // no need to copy
         public float[] mPositions;
-        public boolean mHasSolidColor;
-        public int mSolidColor;
         public int mStrokeWidth = -1;   // if >= 0 use stroking.
-        public int mStrokeColor;
         public float mStrokeDashWidth;
         public float mStrokeDashGap;
         public float mRadius;    // use this if mRadiusArray is null
@@ -1241,10 +1239,8 @@
             if (state.mPositions != null) {
                 mPositions = state.mPositions.clone();
             }
-            mHasSolidColor = state.mHasSolidColor;
-            mSolidColor = state.mSolidColor;
+            mStrokeColorStateList = state.mStrokeColorStateList;
             mStrokeWidth = state.mStrokeWidth;
-            mStrokeColor = state.mStrokeColor;
             mStrokeDashWidth = state.mStrokeDashWidth;
             mStrokeDashGap = state.mStrokeDashGap;
             mRadius = state.mRadius;
@@ -1298,22 +1294,12 @@
         }
 
         public void setColors(int[] colors) {
-            mHasSolidColor = false;
             mColors = colors;
             mColorStateList = null;
             computeOpacity();
         }
-        
-        public void setSolidColor(int argb) {
-            mHasSolidColor = argb != Color.TRANSPARENT;
-            mSolidColor = argb;
-            mColors = null;
-            mColorStateList = null;
-            computeOpacity();
-        }
 
         public void setColorStateList(ColorStateList colorStateList) {
-            mHasSolidColor = false;
             mColors = null;
             mColorStateList = colorStateList;
             computeOpacity();
@@ -1336,9 +1322,6 @@
                         mOpaque = false;
                         return;
                     }
-                } else if (!isOpaque(mStrokeColor)) {
-                    mOpaque = false;
-                    return;
                 }
             }
 
@@ -1347,11 +1330,6 @@
                 return;
             }
 
-            if (mHasSolidColor) {
-                mOpaque = isOpaque(mSolidColor);
-                return;
-            }
-
             if (mColors != null) {
                 for (int i = 0; i < mColors.length; i++) {
                     if (!isOpaque(mColors[i])) {
@@ -1368,22 +1346,6 @@
             return ((color >> 24) & 0xff) == 0xff;
         }
 
-        public void setStroke(int width, int color) {
-            mStrokeWidth = width;
-            mStrokeColor = color;
-            mStrokeColorStateList = null;
-            computeOpacity();
-        }
-
-        public void setStroke(int width, int color, float dashWidth, float dashGap) {
-            mStrokeWidth = width;
-            mStrokeColor = color;
-            mStrokeColorStateList = null;
-            mStrokeDashWidth = dashWidth;
-            mStrokeDashGap = dashGap;
-            computeOpacity();
-        }
-
         public void setStroke(
                 int width, ColorStateList colorStateList, float dashWidth, float dashGap) {
             mStrokeWidth = width;
@@ -1426,9 +1388,7 @@
     }
 
     private void initializeWithState(GradientState state) {
-        if (state.mHasSolidColor) {
-            mFillPaint.setColor(state.mSolidColor);
-        } else if (state.mColorStateList != null) {
+        if (state.mColorStateList != null) {
             final int[] currentState = getState();
             final int stateColor = state.mColorStateList.getColorForState(currentState, 0);
             mFillPaint.setColor(stateColor);
@@ -1451,8 +1411,6 @@
                 final int strokeStateColor = state.mStrokeColorStateList.getColorForState(
                         currentState, 0);
                 mStrokePaint.setColor(strokeStateColor);
-            } else {
-                mStrokePaint.setColor(state.mStrokeColor);
             }
 
             if (state.mStrokeDashWidth != 0.0f) {
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index ee64d7a..515d3c1 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -223,7 +223,7 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    public void draw(Canvas canvas) {
         final Rect bounds = getBounds();
         final boolean needsMirroring = needsMirroring();
         if (needsMirroring) {
diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java
index 2118b23..cb2d8f6 100644
--- a/graphics/java/android/graphics/drawable/PictureDrawable.java
+++ b/graphics/java/android/graphics/drawable/PictureDrawable.java
@@ -60,7 +60,7 @@
     }
     
     @Override
-    protected void onDraw(Canvas canvas) {
+    public void draw(Canvas canvas) {
         if (mPicture != null) {
             Rect bounds = getBounds();
             canvas.save();
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index aec3a4b..630dc2e 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -31,13 +31,14 @@
 import java.io.IOException;
 
 /**
- * <p>A Drawable that can rotate another Drawable based on the current level
- * value. The start and end angles of rotation can be controlled to map any
- * circular arc to the level values range.</p>
- *
- * <p>It can be defined in an XML file with the <code>&lt;rotate></code> element. For more
- * information, see the guide to <a
- * href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p>
+ * <p>
+ * A Drawable that can rotate another Drawable based on the current level value.
+ * The start and end angles of rotation can be controlled to map any circular
+ * arc to the level values range.
+ * <p>
+ * It can be defined in an XML file with the <code>&lt;rotate&gt;</code> element.
+ * For more information, see the guide to
+ * <a href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.
  *
  * @attr ref android.R.styleable#RotateDrawable_visible
  * @attr ref android.R.styleable#RotateDrawable_fromDegrees
@@ -49,20 +50,21 @@
 public class RotateDrawable extends Drawable implements Drawable.Callback {
     private static final float MAX_LEVEL = 10000.0f;
 
-    private RotateState mState;
+    private final RotateState mState;
+
     private boolean mMutated;
 
     /**
-     * <p>Create a new rotating drawable with an empty state.</p>
+     * Create a new rotating drawable with an empty state.
      */
     public RotateDrawable() {
         this(null, null);
     }
 
     /**
-     * <p>Create a new rotating drawable with the specified state. A copy of
+     * Create a new rotating drawable with the specified state. A copy of
      * this state is used as the internal state for the newly created
-     * drawable.</p>
+     * drawable.
      *
      * @param rotateState the state for this drawable
      */
@@ -70,28 +72,42 @@
         mState = new RotateState(rotateState, this, res);
     }
 
+    @Override
     public void draw(Canvas canvas) {
-        int saveCount = canvas.save();
-
-        Rect bounds = mState.mDrawable.getBounds();
-
-        int w = bounds.right - bounds.left;
-        int h = bounds.bottom - bounds.top;
-
         final RotateState st = mState;
-        
-        float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
-        float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
+        final Drawable d = st.mDrawable;
+        final Rect bounds = d.getBounds();
+        final int w = bounds.right - bounds.left;
+        final int h = bounds.bottom - bounds.top;
+        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
 
+        final int saveCount = canvas.save();
         canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top);
-
-        st.mDrawable.draw(canvas);
-
+        d.draw(canvas);
         canvas.restoreToCount(saveCount);
     }
 
     /**
-     * Returns the drawable rotated by this RotateDrawable.
+     * Sets the drawable rotated by this RotateDrawable.
+     *
+     * @param drawable The drawable to rotate
+     */
+    public void setDrawable(Drawable drawable) {
+        final Drawable oldDrawable = mState.mDrawable;
+        if (oldDrawable != drawable) {
+            if (oldDrawable != null) {
+                oldDrawable.setCallback(null);
+            }
+            mState.mDrawable = drawable;
+            if (drawable != null) {
+                drawable.setCallback(this);
+            }
+        }
+    }
+
+    /**
+     * @return The drawable rotated by this RotateDrawable
      */
     public Drawable getDrawable() {
         return mState.mDrawable;
@@ -103,7 +119,8 @@
                 | mState.mChangingConfigurations
                 | mState.mDrawable.getChangingConfigurations();
     }
-    
+
+    @Override
     public void setAlpha(int alpha) {
         mState.mDrawable.setAlpha(alpha);
     }
@@ -113,14 +130,149 @@
         return mState.mDrawable.getAlpha();
     }
 
+    @Override
     public void setColorFilter(ColorFilter cf) {
         mState.mDrawable.setColorFilter(cf);
     }
 
+    @Override
     public int getOpacity() {
         return mState.mDrawable.getOpacity();
     }
 
+    /**
+     * Sets the start angle for rotation.
+     *
+     * @param fromDegrees Starting angle in degrees
+     */
+    public void setFromDegrees(float fromDegrees) {
+        if (mState.mFromDegrees != fromDegrees) {
+            mState.mFromDegrees = fromDegrees;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return The starting angle for rotation in degrees
+     */
+    public float getFromDegrees() {
+        return mState.mFromDegrees;
+    }
+
+    /**
+     * Sets the end angle for rotation.
+     *
+     * @param toDegrees Ending angle in degrees
+     */
+    public void setToDegrees(float toDegrees) {
+        if (mState.mToDegrees != toDegrees) {
+            mState.mToDegrees = toDegrees;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return The ending angle for rotation in degrees
+     */
+    public float getToDegrees() {
+        return mState.mToDegrees;
+    }
+
+    /**
+     * Sets the X position around which the drawable is rotated.
+     *
+     * @param pivotX X position around which to rotate. If the X pivot is
+     *            relative, the position represents a fraction of the drawable
+     *            width. Otherwise, the position represents an absolute value in
+     *            pixels.
+     * @see #setPivotXRelative(boolean)
+     */
+    public void setPivotX(float pivotX) {
+        if (mState.mPivotX == pivotX) {
+            mState.mPivotX = pivotX;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return X position around which to rotate
+     * @see #setPivotX(float)
+     */
+    public float getPivotX() {
+        return mState.mPivotX;
+    }
+
+    /**
+     * Sets whether the X pivot value represents a fraction of the drawable
+     * width or an absolute value in pixels.
+     *
+     * @param relative True if the X pivot represents a fraction of the drawable
+     *            width, or false if it represents an absolute value in pixels
+     */
+    public void setPivotXRelative(boolean relative) {
+        if (mState.mPivotXRel == relative) {
+            mState.mPivotXRel = relative;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return True if the X pivot represents a fraction of the drawable width,
+     *         or false if it represents an absolute value in pixels
+     * @see #setPivotXRelative(boolean)
+     */
+    public boolean isPivotXRelative() {
+        return mState.mPivotXRel;
+    }
+
+    /**
+     * Sets the Y position around which the drawable is rotated.
+     *
+     * @param pivotY Y position around which to rotate. If the Y pivot is
+     *            relative, the position represents a fraction of the drawable
+     *            height. Otherwise, the position represents an absolute value
+     *            in pixels.
+     * @see #setPivotYRelative(boolean)
+     */
+    public void setPivotY(float pivotY) {
+        if (mState.mPivotY == pivotY) {
+            mState.mPivotY = pivotY;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return Y position around which to rotate
+     * @see #setPivotY(float)
+     */
+    public float getPivotY() {
+        return mState.mPivotY;
+    }
+
+    /**
+     * Sets whether the Y pivot value represents a fraction of the drawable
+     * height or an absolute value in pixels.
+     *
+     * @param relative True if the Y pivot represents a fraction of the drawable
+     *            height, or false if it represents an absolute value in pixels
+     */
+    public void setPivotYRelative(boolean relative) {
+        if (mState.mPivotYRel == relative) {
+            mState.mPivotYRel = relative;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return True if the Y pivot represents a fraction of the drawable height,
+     *         or false if it represents an absolute value in pixels
+     * @see #setPivotYRelative(boolean)
+     */
+    public boolean isPivotYRelative() {
+        return mState.mPivotYRel;
+    }
+
+    @Override
     public void invalidateDrawable(Drawable who) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -128,6 +280,7 @@
         }
     }
 
+    @Override
     public void scheduleDrawable(Drawable who, Runnable what, long when) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -135,6 +288,7 @@
         }
     }
 
+    @Override
     public void unscheduleDrawable(Drawable who, Runnable what) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -157,10 +311,10 @@
     public boolean isStateful() {
         return mState.mDrawable.isStateful();
     }
-    
+
     @Override
     protected boolean onStateChange(int[] state) {
-        boolean changed = mState.mDrawable.setState(state);
+        final boolean changed = mState.mDrawable.setState(state);
         onBoundsChange(getBounds());
         return changed;
     }
@@ -172,7 +326,7 @@
 
         mState.mCurrentDegrees = mState.mFromDegrees +
                 (mState.mToDegrees - mState.mFromDegrees) *
-                        ((float) level / MAX_LEVEL);
+                        (level / MAX_LEVEL);
 
         invalidateSelf();
         return true;
@@ -206,16 +360,15 @@
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
             throws XmlPullParserException, IOException {
-
-        TypedArray a = r.obtainAttributes(attrs,
+        final TypedArray a = r.obtainAttributes(attrs,
                 com.android.internal.R.styleable.RotateDrawable);
 
         super.inflateWithAttributes(r, parser, a,
                 com.android.internal.R.styleable.RotateDrawable_visible);
-        
+
         TypedValue tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotX);
-        boolean pivotXRel;
-        float pivotX;
+        final boolean pivotXRel;
+        final float pivotX;
         if (tv == null) {
             pivotXRel = true;
             pivotX = 0.5f;
@@ -223,10 +376,10 @@
             pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
             pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
         }
-        
+
         tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotY);
-        boolean pivotYRel;
-        float pivotY;
+        final boolean pivotYRel;
+        final float pivotY;
         if (tv == null) {
             pivotYRel = true;
             pivotY = 0.5f;
@@ -235,12 +388,12 @@
             pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
         }
 
-        float fromDegrees = a.getFloat(
+        final float fromDegrees = a.getFloat(
                 com.android.internal.R.styleable.RotateDrawable_fromDegrees, 0.0f);
-        float toDegrees = a.getFloat(
+        final float toDegrees = a.getFloat(
                 com.android.internal.R.styleable.RotateDrawable_toDegrees, 360.0f);
 
-        int res = a.getResourceId(
+        final int res = a.getResourceId(
                 com.android.internal.R.styleable.RotateDrawable_drawable, 0);
         Drawable drawable = null;
         if (res > 0) {
@@ -248,8 +401,8 @@
         }
 
         a.recycle();
-        
-        int outerDepth = parser.getDepth();
+
+        final int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
                (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -268,13 +421,15 @@
             Log.w("drawable", "No drawable specified for <rotate>");
         }
 
-        mState.mDrawable = drawable;
-        mState.mPivotXRel = pivotXRel;
-        mState.mPivotX = pivotX;
-        mState.mPivotYRel = pivotYRel;
-        mState.mPivotY = pivotY;
-        mState.mFromDegrees = mState.mCurrentDegrees = fromDegrees;
-        mState.mToDegrees = toDegrees;
+        final RotateState st = mState;
+        st.mDrawable = drawable;
+        st.mPivotXRel = pivotXRel;
+        st.mPivotX = pivotX;
+        st.mPivotYRel = pivotYRel;
+        st.mPivotY = pivotY;
+        st.mFromDegrees = fromDegrees;
+        st.mCurrentDegrees = fromDegrees;
+        st.mToDegrees = toDegrees;
 
         if (drawable != null) {
             drawable.setCallback(this);
@@ -291,15 +446,15 @@
     }
 
     /**
-     * <p>Represents the state of a rotation for a given drawable. The same
+     * Represents the state of a rotation for a given drawable. The same
      * rotate drawable can be invoked with different states to drive several
-     * rotations at the same time.</p>
+     * rotations at the same time.
      */
     final static class RotateState extends Drawable.ConstantState {
         Drawable mDrawable;
 
         int mChangingConfigurations;
-        
+
         boolean mPivotXRel;
         float mPivotX;
         boolean mPivotYRel;
@@ -311,7 +466,7 @@
         float mCurrentDegrees;
 
         private boolean mCanConstantState;
-        private boolean mCheckedConstantState;        
+        private boolean mCheckedConstantState;
 
         public RotateState(RotateState source, RotateDrawable owner, Resources res) {
             if (source != null) {
@@ -336,12 +491,12 @@
         public Drawable newDrawable() {
             return new RotateDrawable(this, null);
         }
-        
+
         @Override
         public Drawable newDrawable(Resources res) {
             return new RotateDrawable(this, res);
         }
-        
+
         @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 9ca3bbf..93f2dc6 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -210,7 +210,7 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    public void draw(Canvas canvas) {
         Rect r = getBounds();
         Paint paint = mShapeState.mPaint;
 
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 09e2058..4c2299e 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -653,11 +653,9 @@
     Vector2 penumbra[k];
     int penumbraLength = hull(shadowRegion, shadowRegionLength, penumbra);
 
-    // no real umbra make a fake one
+    Vector2 fakeUmbra[polyLength];
     if (umbraLength < 3) {
-        // The shadow from the centroid of the light polygon.
-        Vector2 centShadow[polyLength];
-
+        // If there is no real umbra, make a fake one.
         for (int i = 0; i < polyLength; i++) {
             float t = lightCenter.z - poly[i].z;
             if (t == 0) {
@@ -667,23 +665,23 @@
             float x = lightCenter.x - t * (lightCenter.x - poly[i].x);
             float y = lightCenter.y - t * (lightCenter.y - poly[i].y);
 
-            centShadow[i].x = x;
-            centShadow[i].y = y;
+            fakeUmbra[i].x = x;
+            fakeUmbra[i].y = y;
         }
 
         // Shrink the centroid's shadow by 10%.
         // TODO: Study the magic number of 10%.
-        Vector2 shadowCentroid = centroid2d(centShadow, polyLength);
+        Vector2 shadowCentroid = centroid2d(fakeUmbra, polyLength);
         for (int i = 0; i < polyLength; i++) {
-            centShadow[i] = shadowCentroid * (1.0f - SHADOW_SHRINK_SCALE) +
-                    centShadow[i] * SHADOW_SHRINK_SCALE;
+            fakeUmbra[i] = shadowCentroid * (1.0f - SHADOW_SHRINK_SCALE) +
+                    fakeUmbra[i] * SHADOW_SHRINK_SCALE;
         }
 #if DEBUG_SHADOW
         ALOGD("No real umbra make a fake one, centroid2d =  %f , %f",
                 shadowCentroid.x, shadowCentroid.y);
 #endif
         // Set the fake umbra, whose size is the same as the original polygon.
-        umbra = centShadow;
+        umbra = fakeUmbra;
         umbraLength = polyLength;
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 7c0735b..f82ca22 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -591,7 +591,7 @@
                 icon.setImageDrawable(mIcon);
                 icon.setScaleType(ScaleType.CENTER_CROP);
             } else if (mIconResId != 0) {
-                icon.setImageDrawable(context.getResources().getDrawable(mIconResId));
+                icon.setImageDrawable(context.getDrawable(mIconResId));
             }
             if (mMessage != null) {
                 messageView.setText(mMessage);
@@ -681,7 +681,7 @@
 
             boolean on = ((mState == State.On) || (mState == State.TurningOn));
             if (icon != null) {
-                icon.setImageDrawable(context.getResources().getDrawable(
+                icon.setImageDrawable(context.getDrawable(
                         (on ? mEnabledIconResId : mDisabledIconResid)));
                 icon.setEnabled(enabled);
             }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index d0abe9c..c73d90a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -22,6 +22,8 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.*;
 
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.app.ActivityOptions;
 import android.transition.Scene;
 import android.transition.Transition;
@@ -88,6 +90,7 @@
 import android.view.ViewParent;
 import android.view.ViewRootImpl;
 import android.view.ViewStub;
+import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
@@ -114,6 +117,8 @@
     private final static String TAG = "PhoneWindow";
 
     private final static boolean SWEEP_OPEN_MENU = false;
+    private static final long MAX_TRANSITION_START_WAIT = 500;
+    private static final long MAX_TRANSITION_FINISH_WAIT = 1000;
 
     /**
      * Simple callback used by the context menu and its submenus. The options
@@ -136,22 +141,21 @@
     private ViewGroup mContentParent;
 
     SurfaceHolder.Callback2 mTakeSurfaceCallback;
-    
+
     InputQueue.Callback mTakeInputQueueCallback;
-    
+
     private boolean mIsFloating;
 
     private LayoutInflater mLayoutInflater;
 
     private TextView mTitleView;
-    
+
     private ActionBarView mActionBar;
     private ActionMenuPresenterCallback mActionMenuPresenterCallback;
     private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
 
     private TransitionManager mTransitionManager;
     private Scene mContentScene;
-    private Bundle mTransitionOptions;
 
     // The icon resource has been explicitly set elsewhere
     // and should not be overwritten with a default.
@@ -233,6 +237,10 @@
         }
     };
 
+    private ActivityOptions mActivityOptions;
+    private SceneTransitionListener mSceneTransitionListener;
+    private boolean mFadeEarly = true;
+
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService("window"));
@@ -303,11 +311,6 @@
     }
 
     @Override
-    public void setTransitionOptions(Bundle options) {
-        mTransitionOptions = options;
-    }
-
-    @Override
     public void setContentView(int layoutResID) {
         // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
         // decor, when theme attributes and the like are crystalized. Do not check the feature
@@ -378,26 +381,11 @@
     }
 
     private void transitionTo(Scene scene) {
-        Transition selected = null;
-        if (mTransitionOptions != null) {
-            final ActivityOptions opts = new ActivityOptions(mTransitionOptions);
-            mTransitionOptions = null;
-
-            String selectedName = null;
-            for (String sceneName : opts.getDestSceneNames()) {
-                final Transition t = mTransitionManager.getNamedTransition(sceneName, scene);
-                if (t != null) {
-                    // TODO handle args/state; inject into t/clone with params
-                    selected = t;
-                    selectedName = sceneName;
-                    break;
-                }
+        if (mContentScene == null) {
+            scene.enter();
+            if (mActivityOptions != null) {
+                new EnterScene().start();
             }
-            opts.dispatchSceneTransitionStarted(selectedName);
-        }
-
-        if (selected != null) {
-            TransitionManager.go(scene, selected);
         } else {
             mTransitionManager.transitionTo(scene);
         }
@@ -413,11 +401,11 @@
     public void takeSurface(SurfaceHolder.Callback2 callback) {
         mTakeSurfaceCallback = callback;
     }
-    
+
     public void takeInputQueue(InputQueue.Callback callback) {
         mTakeInputQueueCallback = callback;
     }
-    
+
     @Override
     public boolean isFloating() {
         return mIsFloating;
@@ -704,7 +692,7 @@
                 // Otherwise, set the normal panel background
                 backgroundResId = st.background;
             }
-            st.decorView.setWindowBackground(getContext().getResources().getDrawable(
+            st.decorView.setWindowBackground(getContext().getDrawable(
                     backgroundResId));
 
             ViewParent shownPanelParent = st.shownPanelView.getParent();
@@ -1289,7 +1277,7 @@
             if (st.resid != resId) {
                 st.resid = resId;
                 st.uri = null;
-                st.local = getContext().getResources().getDrawable(resId);
+                st.local = getContext().getDrawable(resId);
                 updateDrawable(featureId, st, false);
             }
         } else {
@@ -2305,7 +2293,7 @@
                     if (mMenuBackground == null && mFeatureId < 0
                             && getAttributes().height
                             == WindowManager.LayoutParams.MATCH_PARENT) {
-                        mMenuBackground = getContext().getResources().getDrawable(
+                        mMenuBackground = getContext().getDrawable(
                                 com.android.internal.R.drawable.menu_background);
                     }
                     if (mMenuBackground != null) {
@@ -3122,12 +3110,12 @@
         if (getContainer() == null) {
             Drawable drawable = mBackgroundDrawable;
             if (mBackgroundResource != 0) {
-                drawable = getContext().getResources().getDrawable(mBackgroundResource);
+                drawable = getContext().getDrawable(mBackgroundResource);
             }
             mDecor.setWindowBackground(drawable);
             drawable = null;
             if (mFrameResource != 0) {
-                drawable = getContext().getResources().getDrawable(mFrameResource);
+                drawable = getContext().getDrawable(mFrameResource);
             }
             mDecor.setWindowFrame(drawable);
 
@@ -3553,6 +3541,12 @@
         return mVolumeControlStreamType;
     }
 
+    private boolean isTranslucent() {
+        TypedArray a = getWindowStyle();
+        return a.getBoolean(a.getResourceId(
+                com.android.internal.R.styleable.Window_windowIsTranslucent, 0), false);
+    }
+
     private static final class DrawableFeatureState {
         DrawableFeatureState(int _featureId) {
             featureId = _featureId;
@@ -3986,4 +3980,218 @@
     void sendCloseSystemWindows(String reason) {
         PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
     }
+
+    @Override
+    public void setTransitionOptions(ActivityOptions options, SceneTransitionListener listener) {
+        mSceneTransitionListener = listener;
+        mActivityOptions = options;
+    }
+
+    @Override
+    public void setEarlyBackgroundTransition(boolean fadeEarly) {
+        mFadeEarly = fadeEarly;
+    }
+
+    @Override
+    public void startExitTransition(ActivityOptions activityOptions) {
+        Transition transition = mTransitionManager.getNamedTransition(getContentScene(), "null");
+        if (transition == null) {
+            transition = TransitionManager.getDefaultTransition().clone();
+        }
+        activityOptions.setExitTransition(transition, new ActivityOptions.SharedElementSource() {
+            @Override
+            public int getTextureId() {
+                // TODO: move shared elements to a layer and return the texture id
+                recurseHideExitingSharedElements(mContentParent);
+                return 0;
+            }
+        });
+        ViewGroup sceneRoot = getContentScene().getSceneRoot();
+        TransitionManager.beginDelayedTransition(sceneRoot, transition);
+        recurseExitNonSharedElements(mContentParent);
+    }
+
+    private static void recurseExitNonSharedElements(ViewGroup viewGroup) {
+        int numChildren = viewGroup.getChildCount();
+        for (int i = 0; i < numChildren; i++) {
+            View child = viewGroup.getChildAt(i);
+            if (child.getSharedElementName() != null || (child.getVisibility() != View.VISIBLE)) {
+                continue;
+            }
+            if (child instanceof ViewGroup && !((ViewGroup)child).isTransitionGroup()) {
+                recurseExitNonSharedElements((ViewGroup) child);
+            } else {
+                child.setVisibility(View.INVISIBLE);
+            }
+        }
+    }
+
+    private static void recurseHideViews(ViewGroup viewGroup, ArrayList<View> nonSharedElements,
+            ArrayList<View> sharedElements) {
+        int numChildren = viewGroup.getChildCount();
+        for (int i = 0; i < numChildren; i++) {
+            View child = viewGroup.getChildAt(i);
+            if (child.getVisibility() != View.VISIBLE) {
+                continue;
+            }
+            if (child.getSharedElementName() != null) {
+                sharedElements.add(child);
+                child.setVisibility(View.INVISIBLE);
+            } else if (child instanceof ViewGroup && !((ViewGroup)child).isTransitionGroup()) {
+                recurseHideViews((ViewGroup) child, nonSharedElements, sharedElements);
+            } else {
+                nonSharedElements.add(child);
+                child.setVisibility(View.INVISIBLE);
+            }
+        }
+    }
+
+    private static void recurseHideExitingSharedElements(ViewGroup viewGroup) {
+        int numChildren = viewGroup.getChildCount();
+        for (int i = 0; i < numChildren; i++) {
+            View child = viewGroup.getChildAt(i);
+            if (child.getVisibility() != View.VISIBLE) {
+                continue;
+            }
+            if (child.getSharedElementName() != null) {
+                child.setVisibility(View.INVISIBLE);
+            } else if (child instanceof ViewGroup) {
+                ViewGroup childViewGroup = (ViewGroup) child;
+                recurseHideExitingSharedElements(childViewGroup);
+            }
+        }
+    }
+
+    /**
+     * Provides code for handling the Activity transition entering scene.
+     * When the first scene is laid out (onPreDraw), it makes views invisible.
+     * It then starts the entering transition by making non-shared elements visible. When
+     * the entering transition is started, the calling Activity is notified that
+     * this Activity is ready to receive the shared element. When the calling Activity notifies
+     * that the shared element is ready, this Activity is notified through the
+     * SceneTransitionListener.
+     *
+     * This class also takes into account fading the background -- either waiting until the
+     * shared element is ready or the calling Activity's exit transition is complete.
+     */
+    private class EnterScene implements ViewTreeObserver.OnPreDrawListener, Runnable,
+            ActivityOptions.ActivityTransitionTarget, Animator.AnimatorListener {
+        private boolean mSharedElementReadyReceived;
+        private boolean mAllDone;
+        private Handler mHandler = new Handler();
+        private boolean mEnterTransitionStarted;
+        private ArrayList<View> mSharedElements = new ArrayList<View>();
+
+        public EnterScene() {
+            mSceneTransitionListener.nullPendingTransition();
+            Drawable background = getDecorView().getBackground();
+            if (background != null) {
+                setBackgroundDrawable(null);
+                background.setAlpha(0);
+                setBackgroundDrawable(background);
+            }
+            mSceneTransitionListener.convertToTranslucent();
+        }
+
+        @Override
+        public boolean onPreDraw() {
+            ViewTreeObserver observer = mContentParent.getViewTreeObserver();
+            observer.removeOnPreDrawListener(this);
+            if (!mEnterTransitionStarted && mSceneTransitionListener != null) {
+                mEnterTransitionStarted = true;
+                ArrayList<View> enteringViews = new ArrayList<View>();
+                recurseHideViews(mContentParent, enteringViews, mSharedElements);
+                Transition transition = getTransitionManager().getNamedTransition("null",
+                        mContentScene);
+                if (transition == null) {
+                    transition = TransitionManager.getDefaultTransition().clone();
+                }
+                TransitionManager.beginDelayedTransition(mContentParent, transition);
+                for (View hidden : enteringViews) {
+                    hidden.setVisibility(View.VISIBLE);
+                }
+                observer.addOnPreDrawListener(this);
+            } else {
+                mHandler.postDelayed(this, MAX_TRANSITION_START_WAIT);
+                mActivityOptions.dispatchSceneTransitionStarted(this);
+            }
+            return true;
+        }
+
+        public void start() {
+            ViewTreeObserver observer = mContentParent.getViewTreeObserver();
+            observer.addOnPreDrawListener(this);
+        }
+
+        @Override
+        public void run() {
+            exitTransitionComplete();
+        }
+
+        @Override
+        public void sharedElementTransitionComplete() {
+            if (!mSharedElementReadyReceived) {
+                mSharedElementReadyReceived = true;
+                mHandler.removeCallbacks(this);
+                mHandler.postDelayed(this, MAX_TRANSITION_FINISH_WAIT);
+                for (View sharedElement: mSharedElements) {
+                    sharedElement.setVisibility(View.VISIBLE);
+                }
+                mSharedElements.clear();
+                mContentParent.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        mContentParent.getViewTreeObserver().removeOnPreDrawListener(this);
+                        mSceneTransitionListener.enterSharedElement(
+                                mActivityOptions.getSceneTransitionArgs());
+                        return false;
+                    }
+                });
+                if (mFadeEarly) {
+                    fadeInBackground();
+                }
+            }
+        }
+
+        private void fadeInBackground() {
+            Drawable background = getDecorView().getBackground();
+            if (background == null) {
+                mSceneTransitionListener.convertFromTranslucent();
+            } else {
+                ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
+                animator.addListener(this);
+                animator.start();
+            }
+        }
+
+        @Override
+        public void exitTransitionComplete() {
+            if (mAllDone) {
+                return;
+            }
+            mAllDone = true;
+            sharedElementTransitionComplete();
+            mHandler.removeCallbacks(this);
+            if (!mFadeEarly) {
+                fadeInBackground();
+            }
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mSceneTransitionListener.convertFromTranslucent();
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8e83255..ce6166a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -5040,7 +5040,6 @@
     @Override
     public void keepScreenOnStoppedLw() {
         if (mKeyguardDelegate != null && !mKeyguardDelegate.isShowingAndNotHidden()) {
-            long curTime = SystemClock.uptimeMillis();
             mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
         }
     }
diff --git a/preloaded-classes b/preloaded-classes
index 42412c6..4d79e4b 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -2455,8 +2455,6 @@
 org.apache.harmony.security.fortress.Engine$SpiAndProvider
 org.apache.harmony.security.fortress.SecurityAccess
 org.apache.harmony.security.fortress.Services
-org.apache.harmony.security.provider.cert.DRLCertFactory
-org.apache.harmony.security.provider.cert.X509CertImpl
 org.apache.harmony.security.provider.crypto.CryptoProvider
 org.apache.harmony.security.utils.AlgNameMapper
 org.apache.harmony.security.utils.ObjectIdentifier
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 015185f..9349730 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -169,9 +169,9 @@
     private static final String TAG = "ConnectivityService";
 
     private static final boolean DBG = true;
-    private static final boolean VDBG = false;
+    private static final boolean VDBG = true;
 
-    private static final boolean LOGD_RULES = false;
+    private static final boolean LOGD_RULES = true;
 
     // TODO: create better separation between radio types and network types
 
@@ -4495,11 +4495,16 @@
          * @param seconds
          */
         private static void sleep(int seconds) {
-            try {
-                Thread.sleep(seconds * 1000);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
+            log("XXXXX sleeping for " + seconds + " sec");
+            long stopTime = System.nanoTime() + (seconds * 1000000000);
+            long sleepTime;
+            while ((sleepTime = stopTime - System.nanoTime()) > 0) {
+                try {
+                    Thread.sleep(sleepTime / 1000000);
+                } catch (InterruptedException ignored) {
+                }
             }
+            log("XXXXX returning from sleep");
         }
 
         private static void log(String s) {
diff --git a/services/core/java/com/android/server/IdleMaintenanceService.java b/services/core/java/com/android/server/IdleMaintenanceService.java
index b0a1aca..acc6abe 100644
--- a/services/core/java/com/android/server/IdleMaintenanceService.java
+++ b/services/core/java/com/android/server/IdleMaintenanceService.java
@@ -16,22 +16,38 @@
 
 package com.android.server;
 
-import android.app.Activity;
-import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
+import android.app.maintenance.IIdleCallback;
+import android.app.maintenance.IIdleService;
+import android.app.maintenance.IdleService;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.WorkSource;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
 
 /**
  * This service observes the device state and when applicable sends
@@ -47,12 +63,15 @@
  *
  * The end of a maintenance window is announced only if: a start was
  * announced AND the screen turned on or a dream was stopped.
+ *
+ * Method naming note:
+ * Methods whose name ends with "Tm" must only be called from the main thread.
  */
 public class IdleMaintenanceService extends BroadcastReceiver {
 
     private static final boolean DEBUG = false;
 
-    private static final String LOG_TAG = IdleMaintenanceService.class.getSimpleName();
+    private static final String TAG = IdleMaintenanceService.class.getSimpleName();
 
     private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1;
 
@@ -74,36 +93,480 @@
     private static final String ACTION_FORCE_IDLE_MAINTENANCE =
         "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE";
 
-    private static final Intent sIdleMaintenanceStartIntent;
-    static {
-        sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START);
-        sIdleMaintenanceStartIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-    };
+    static final int MSG_OP_COMPLETE = 1;
+    static final int MSG_IDLE_FINISHED = 2;
+    static final int MSG_TIMEOUT = 3;
 
-    private static final Intent sIdleMaintenanceEndIntent;
-    static {
-        sIdleMaintenanceEndIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_END);
-        sIdleMaintenanceEndIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-    }
+    // when a timeout happened, what were we expecting?
+    static final int VERB_BINDING = 1;
+    static final int VERB_IDLING = 2;
+    static final int VERB_ENDING = 3;
+
+    // What are our relevant timeouts / allocated slices?
+    static final long OP_TIMEOUT = 8 * 1000;  // 8 seconds to bind or ack the start
+    static final long IDLE_TIMESLICE = 10 * 60 * 1000;  // ten minutes for each idler
 
     private final AlarmManager mAlarmService;
-
     private final BatteryService mBatteryService;
-
     private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent;
-
     private final Context mContext;
-
     private final WakeLock mWakeLock;
-
-    private final Handler mHandler;
+    private final WorkSource mSystemWorkSource = new WorkSource(Process.myUid());
 
     private long mLastIdleMaintenanceStartTimeMillis;
-
     private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
-
     private boolean mIdleMaintenanceStarted;
 
+    final IdleCallback mCallback;
+    final Handler mHandler;
+
+    final Random mTokenGenerator = new Random();
+
+    int makeToken() {
+        int token;
+        do  {
+            token = mTokenGenerator.nextInt(Integer.MAX_VALUE);
+        } while (token == 0);
+        return token;
+    }
+
+    class ActiveTask {
+        public IdleServiceInfo who;
+        public int verb;
+        public int token;
+
+        ActiveTask(IdleServiceInfo target, int action) {
+            who = target;
+            verb = action;
+            token = makeToken();
+        }
+
+        @Override
+        public String toString() {
+            return "ActiveTask{" + Integer.toHexString(this.hashCode())
+                    + " : verb=" + verb
+                    + " : token=" + token
+                    + " : "+ who + "}";
+        }
+    }
+
+    // What operations are in flight?
+    final SparseArray<ActiveTask> mPendingOperations = new SparseArray<ActiveTask>();
+
+    // Idle service queue management
+    class IdleServiceInfo {
+        public final ComponentName componentName;
+        public final int uid;
+        public IIdleService service;
+
+        IdleServiceInfo(ResolveInfo info, ComponentName cname) {
+            componentName = cname;  // derived from 'info' but this avoids an extra object
+            uid = info.serviceInfo.applicationInfo.uid;
+            service = null;
+        }
+
+        @Override
+        public int hashCode() {
+            return componentName.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return "IdleServiceInfo{" + componentName
+                    + " / " + (service == null ? "null" : service.asBinder()) + "}";
+        }
+    }
+
+    final ArrayMap<ComponentName, IdleServiceInfo> mIdleServices =
+            new ArrayMap<ComponentName, IdleServiceInfo>();
+    final LinkedList<IdleServiceInfo> mIdleServiceQueue = new LinkedList<IdleServiceInfo>();
+    IdleServiceInfo mCurrentIdler;  // set when we've committed to launching an idler
+    IdleServiceInfo mLastIdler;     // end of queue when idling begins
+
+    void reportNoTimeout(int token, boolean result) {
+        final Message msg = mHandler.obtainMessage(MSG_OP_COMPLETE, result ? 1 : 0, token);
+        mHandler.sendMessage(msg);
+    }
+
+    // Binder acknowledgment trampoline
+    class IdleCallback extends IIdleCallback.Stub {
+        @Override
+        public void acknowledgeStart(int token, boolean result) throws RemoteException {
+            reportNoTimeout(token, result);
+        }
+
+        @Override
+        public void acknowledgeStop(int token) throws RemoteException {
+            reportNoTimeout(token, false);
+        }
+
+        @Override
+        public void idleFinished(int token) throws RemoteException {
+            if (DEBUG) {
+                Slog.v(TAG, "idleFinished: " + token);
+            }
+            final Message msg = mHandler.obtainMessage(MSG_IDLE_FINISHED, 0, token);
+            mHandler.sendMessage(msg);
+        }
+    }
+
+    // Stuff that we run on a Handler
+    class IdleHandler extends Handler {
+        public IdleHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            final int token = msg.arg2;
+
+            switch (msg.what) {
+                case MSG_OP_COMPLETE: {
+                    if (DEBUG) {
+                        Slog.i(TAG, "MSG_OP_COMPLETE of " + token);
+                    }
+                    ActiveTask task = mPendingOperations.get(token);
+                    if (task != null) {
+                        mPendingOperations.remove(token);
+                        removeMessages(MSG_TIMEOUT);
+
+                        handleOpCompleteTm(task, msg.arg1);
+                    } else {
+                        // Can happen in a race between timeout and actual
+                        // (belated) completion of a "begin idling" or similar
+                        // operation.  In that state we've already processed the
+                        // timeout, so we intentionally no-op here.
+                        if (DEBUG) {
+                            Slog.w(TAG, "Belated op-complete of " + token);
+                        }
+                    }
+                    break;
+                }
+
+                case MSG_IDLE_FINISHED: {
+                    if (DEBUG) {
+                        Slog.i(TAG, "MSG_IDLE_FINISHED of " + token);
+                    }
+                    ActiveTask task = mPendingOperations.get(token);
+                    if (task != null) {
+                        if (DEBUG) {
+                            Slog.i(TAG, "... removing task " + token);
+                        }
+                        mPendingOperations.remove(token);
+                        removeMessages(MSG_TIMEOUT);
+
+                        handleIdleFinishedTm(task);
+                    } else {
+                        // Can happen "legitimately" from an app explicitly calling
+                        // idleFinished() after already having been told that its slice
+                        // has ended.
+                        if (DEBUG) {
+                            Slog.w(TAG, "Belated idle-finished of " + token);
+                        }
+                    }
+                    break;
+                }
+
+                case MSG_TIMEOUT: {
+                    if (DEBUG) {
+                        Slog.i(TAG, "MSG_TIMEOUT of " + token);
+                    }
+                    ActiveTask task = mPendingOperations.get(token);
+                    if (task != null) {
+                        mPendingOperations.remove(token);
+                        removeMessages(MSG_OP_COMPLETE);
+
+                        handleTimeoutTm(task);
+                    } else {
+                        // This one should not happen; we flushed timeout messages
+                        // whenever we entered a state after which we have established
+                        // that they are not appropriate.
+                        Slog.w(TAG, "Unexpected timeout of " + token);
+                    }
+                    break;
+                }
+
+                default:
+                    Slog.w(TAG, "Unknown message: " + msg.what);
+            }
+        }
+    }
+
+    void handleTimeoutTm(ActiveTask task) {
+        switch (task.verb) {
+        case VERB_BINDING: {
+            // We were trying to bind to this service, but it wedged or otherwise
+            // failed to respond in time.  Let it stay in the queue for the next
+            // time around, but just give up on it for now and go on to the next.
+            startNextIdleServiceTm();
+            break;
+        }
+        case VERB_IDLING: {
+            // The service has reached the end of its designated idle timeslice.
+            // This is not considered an error.
+            if (DEBUG) {
+                Slog.i(TAG, "Idler reached end of timeslice: " + task.who);
+            }
+            sendEndIdleTm(task.who);
+            break;
+        }
+        case VERB_ENDING: {
+            if (mCurrentIdler == task.who) {
+                if (DEBUG) {
+                    Slog.i(TAG, "Task timed out when ending; unbind needed");
+                }
+                handleIdleFinishedTm(task);
+            } else {
+                if (DEBUG) {
+                    Slog.w(TAG, "Ending timeout for non-current idle service!");
+                }
+            }
+            break;
+        }
+        default: {
+            Slog.w(TAG, "Unknown timeout state " + task.verb);
+            break;
+        }
+        }
+    }
+
+    void handleOpCompleteTm(ActiveTask task, int result) {
+        if (DEBUG) {
+            Slog.i(TAG, "handleOpComplete : task=" + task + " result=" + result);
+        }
+        if (task.verb == VERB_IDLING) {
+            // If the service was told to begin idling and responded positively, then
+            // it has begun idling and will eventually either explicitly finish, or
+            // reach the end of its allotted timeslice.  It's running free now, so we
+            // just schedule the idle-expiration timeout under the token it's already been
+            // given and let it keep going.
+            if (result != 0) {
+                scheduleOpTimeoutTm(task);
+            } else {
+                // The idle service has indicated that it does not, in fact,
+                // need to run at present, so we immediately indicate that it's
+                // to finish idling, and go on to the next idler.
+                if (DEBUG) {
+                    Slog.i(TAG, "Idler declined idling; moving along");
+                }
+                sendEndIdleTm(task.who);
+            }
+        } else {
+            // In the idling case, the task will be cleared either as the result of a timeout
+            // or of an explicit idleFinished().  For all other operations (binding, ending) we
+            // are done with the task as such, so we remove it from our bookkeeping.
+            if (DEBUG) {
+                Slog.i(TAG, "Clearing task " + task);
+            }
+            mPendingOperations.remove(task.token);
+            if (task.verb == VERB_ENDING) {
+                // The last bit of handshaking around idle cessation for this target
+                handleIdleFinishedTm(task);
+            }
+        }
+    }
+
+    void handleIdleFinishedTm(ActiveTask task) {
+        final IdleServiceInfo who = task.who;
+        if (who == mCurrentIdler) {
+            if (DEBUG) {
+                Slog.i(TAG, "Current idler has finished: " + who);
+                Slog.i(TAG, "Attributing wakelock to system work source");
+            }
+            mContext.unbindService(mConnection);
+            startNextIdleServiceTm();
+        } else {
+            Slog.w(TAG, "finish from non-current idle service? " + who);
+        }
+    }
+
+    void updateIdleServiceQueueTm() {
+        if (DEBUG) {
+            Slog.i(TAG, "Updating idle service queue");
+        }
+        PackageManager pm = mContext.getPackageManager();
+        Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
+        List<ResolveInfo> services = pm.queryIntentServices(idleIntent, 0);
+        for (ResolveInfo info : services) {
+            if (info.serviceInfo != null) {
+                if (IdleService.PERMISSION_BIND.equals(info.serviceInfo.permission)) {
+                    final ComponentName componentName = new ComponentName(
+                            info.serviceInfo.packageName,
+                            info.serviceInfo.name);
+                    if (DEBUG) {
+                        Slog.i(TAG, "   - " + componentName);
+                    }
+                    if (!mIdleServices.containsKey(componentName)) {
+                        if (DEBUG) {
+                            Slog.i(TAG, "      + not known; adding");
+                        }
+                        IdleServiceInfo serviceInfo = new IdleServiceInfo(info, componentName);
+                        mIdleServices.put(componentName, serviceInfo);
+                        mIdleServiceQueue.add(serviceInfo);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.i(TAG, "Idle service " + info.serviceInfo
+                                + " does not have required permission; ignoring");
+                    }
+                }
+            }
+        }
+    }
+
+    void startNextIdleServiceTm() {
+        mWakeLock.setWorkSource(mSystemWorkSource);
+
+        if (mLastIdler == null) {
+            // we've run the queue; nothing more to do until the next idle interval.
+            if (DEBUG) {
+                Slog.i(TAG, "Queue already drained; nothing more to do");
+            }
+            return;
+        }
+
+        if (DEBUG) {
+            Slog.i(TAG, "startNextIdleService : last=" + mLastIdler + " cur=" + mCurrentIdler);
+            if (mIdleServiceQueue.size() > 0) {
+                int i = 0;
+                Slog.i(TAG, "Queue (" + mIdleServiceQueue.size() + "):");
+                for (IdleServiceInfo info : mIdleServiceQueue) {
+                    Slog.i(TAG, "   " + i + " : " + info);
+                    i++;
+                }
+            }
+        }
+        if (mCurrentIdler != mLastIdler) {
+            if (mIdleServiceQueue.size() > 0) {
+                IdleServiceInfo target = mIdleServiceQueue.pop();
+                if (DEBUG) {
+                    Slog.i(TAG, "starting next idle service " + target);
+                }
+                Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
+                idleIntent.setComponent(target.componentName);
+                mCurrentIdler = target;
+                ActiveTask task = new ActiveTask(target, VERB_BINDING);
+                scheduleOpTimeoutTm(task);
+                boolean bindOk = mContext.bindServiceAsUser(idleIntent, mConnection,
+                        Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY, UserHandle.OWNER);
+                if (!bindOk) {
+                    if (DEBUG) {
+                        Slog.w(TAG, "bindService() to " + target.componentName
+                                + " failed");
+                    }
+                } else {
+                    mIdleServiceQueue.add(target);  // at the end for next time
+                    if (DEBUG) { Slog.i(TAG, "Attributing wakelock to target uid " + target.uid); }
+                    mWakeLock.setWorkSource(new WorkSource(target.uid));
+                }
+            } else {
+                // Queue is empty but mLastIdler is non-null -- eeep.  Clear *everything*
+                // and wind up until the next time around.
+                Slog.e(TAG, "Queue unexpectedly empty; resetting.  last="
+                        + mLastIdler + " cur=" + mCurrentIdler);
+                mHandler.removeMessages(MSG_TIMEOUT);
+                mPendingOperations.clear();
+                stopIdleMaintenanceTm();
+            }
+        } else {
+            // we've reached the place we started, so mark the queue as drained
+            if (DEBUG) {
+                Slog.i(TAG, "Reached end of queue.");
+            }
+            stopIdleMaintenanceTm();
+        }
+    }
+
+    void sendStartIdleTm(IdleServiceInfo who) {
+        ActiveTask task = new ActiveTask(who, VERB_IDLING);
+        scheduleOpTimeoutTm(task);
+        try {
+            who.service.startIdleMaintenance(mCallback, task.token);
+        } catch (RemoteException e) {
+            // We bound to it, but now we can't reach it.  Bail and go on to the
+            // next service.
+            mContext.unbindService(mConnection);
+            if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
+            mHandler.removeMessages(MSG_TIMEOUT);
+            startNextIdleServiceTm();
+        }
+    }
+
+    void sendEndIdleTm(IdleServiceInfo who) {
+        ActiveTask task = new ActiveTask(who, VERB_ENDING);
+        scheduleOpTimeoutTm(task);
+        if (DEBUG) {
+            Slog.i(TAG, "Sending end-idle to " + who);
+        }
+        try {
+            who.service.stopIdleMaintenance(mCallback, task.token);
+        } catch (RemoteException e) {
+            // We bound to it, but now we can't reach it.  Bail and go on to the
+            // next service.
+            mContext.unbindService(mConnection);
+            if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
+            mHandler.removeMessages(MSG_TIMEOUT);
+            startNextIdleServiceTm();
+        }
+    }
+
+    ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (DEBUG) {
+                Slog.i(TAG, "onServiceConnected(" + name + ")");
+            }
+            IdleServiceInfo info = mIdleServices.get(name);
+            if (info != null) {
+                // Bound!  Cancel the bind timeout
+                mHandler.removeMessages(MSG_TIMEOUT);
+                // Now tell it to start its idle work
+                info.service = IIdleService.Stub.asInterface(service);
+                sendStartIdleTm(info);
+            } else {
+                // We bound to a service we don't know about.  That's ungood.
+                Slog.e(TAG, "Connected to unexpected component " + name);
+                mContext.unbindService(this);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) {
+                Slog.i(TAG, "onServiceDisconnected(" + name + ")");
+            }
+            IdleServiceInfo who = mIdleServices.get(name);
+            if (who == mCurrentIdler) {
+                // Hm, okay; they didn't tell us they were finished but they
+                // went away.  Crashed, probably.  Oh well.  They're gone, so
+                // we can't finish them cleanly; just force things along.
+                Slog.w(TAG, "Idler unexpectedly vanished: " + mCurrentIdler);
+                mContext.unbindService(this);
+                mHandler.removeMessages(MSG_TIMEOUT);
+                startNextIdleServiceTm();
+            } else {
+                // Not the current idler, so we don't interrupt our process...
+                if (DEBUG) {
+                    Slog.w(TAG, "Disconnect of abandoned or unexpected service " + name);
+                }
+            }
+        }
+    };
+
+    // Schedules a timeout / end-of-work based on the task verb
+    void scheduleOpTimeoutTm(ActiveTask task) {
+        final long timeoutMillis = (task.verb == VERB_IDLING) ? IDLE_TIMESLICE : OP_TIMEOUT;
+        if (DEBUG) {
+            Slog.i(TAG, "Scheduling timeout (token " + task.token
+                    + " : verb " + task.verb + ") for " + task + " in " + timeoutMillis);
+        }
+        mPendingOperations.put(task.token, task);
+        mHandler.removeMessages(MSG_TIMEOUT);
+        final Message msg = mHandler.obtainMessage(MSG_TIMEOUT, 0, task.token);
+        mHandler.sendMessageDelayed(msg, timeoutMillis);
+    }
+
+    // -------------------------------------------------------------------------------
     public IdleMaintenanceService(Context context, BatteryService batteryService) {
         mContext = context;
         mBatteryService = batteryService;
@@ -111,9 +574,10 @@
         mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
 
         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
+        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 
-        mHandler = new Handler(mContext.getMainLooper());
+        mHandler = new IdleHandler(mContext.getMainLooper());
+        mCallback = new IdleCallback();
 
         Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
         intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -159,26 +623,28 @@
         mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
     }
 
-    private void updateIdleMaintenanceState(boolean noisy) {
+    private void updateIdleMaintenanceStateTm(boolean noisy) {
         if (mIdleMaintenanceStarted) {
             // Idle maintenance can be interrupted by user activity, or duration
             // time out, or low battery.
-            if (!lastUserActivityPermitsIdleMaintenanceRunning()
-                    || !batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) {
+            final boolean batteryOk
+                    = batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning();
+            if (!lastUserActivityPermitsIdleMaintenanceRunning() || !batteryOk) {
                 unscheduleUpdateIdleMaintenanceState();
                 mIdleMaintenanceStarted = false;
-                EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(),
-                        mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
-                        isBatteryCharging() ? 1 : 0);
-                sendIdleMaintenanceEndIntent();
                 // We stopped since we don't have enough battery or timed out but the
                 // user is not using the device, so we should be able to run maintenance
                 // in the next maintenance window since the battery may be charged
                 // without interaction and the min interval between maintenances passed.
-                if (!batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) {
+                if (!batteryOk) {
                     scheduleUpdateIdleMaintenanceState(
                             getNextIdleMaintenanceIntervalStartFromNow());
                 }
+
+                EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(),
+                        mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
+                        isBatteryCharging() ? 1 : 0);
+                scheduleIdleFinishTm();
             }
         } else if (deviceStatePermitsIdleMaintenanceStart(noisy)
                 && lastUserActivityPermitsIdleMaintenanceStart(noisy)
@@ -191,7 +657,7 @@
                     mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
                     isBatteryCharging() ? 1 : 0);
             mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
-            sendIdleMaintenanceStartIntent();
+            startIdleMaintenanceTm();
         } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) {
              if (lastRunPermitsIdleMaintenanceStart(noisy)) {
                 // The user does not use the device and we did not run maintenance in more
@@ -207,27 +673,57 @@
         }
     }
 
+    void startIdleMaintenanceTm() {
+        if (DEBUG) {
+            Slog.i(TAG, "*** Starting idle maintenance ***");
+        }
+        if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
+        mWakeLock.setWorkSource(mSystemWorkSource);
+        mWakeLock.acquire();
+        updateIdleServiceQueueTm();
+        mCurrentIdler = null;
+        mLastIdler = (mIdleServiceQueue.size() > 0) ? mIdleServiceQueue.peekLast() : null;
+        startNextIdleServiceTm();
+    }
+
+    // Start a graceful wind-down of the idle maintenance state: end the current idler
+    // and pretend that we've finished running the queue.  If there's no current idler,
+    // this is a no-op.
+    void scheduleIdleFinishTm() {
+        if (mCurrentIdler != null) {
+            if (DEBUG) {
+                Slog.i(TAG, "*** Finishing idle maintenance ***");
+            }
+            mLastIdler = mCurrentIdler;
+            sendEndIdleTm(mCurrentIdler);
+        } else {
+            if (DEBUG) {
+                Slog.w(TAG, "Asked to finish idle maintenance but we're done already");
+            }
+        }
+    }
+
+    // Actual finalization of the idle maintenance sequence
+    void stopIdleMaintenanceTm() {
+        if (mLastIdler != null) {
+            if (DEBUG) {
+                Slog.i(TAG, "*** Idle maintenance shutdown ***");
+            }
+            mWakeLock.setWorkSource(mSystemWorkSource);
+            mLastIdler = mCurrentIdler = null;
+            updateIdleMaintenanceStateTm(false);   // resets 'started' and schedules next window
+            mWakeLock.release();
+        } else {
+            Slog.e(TAG, "ERROR: idle shutdown but invariants not held.  last=" + mLastIdler
+                    + " cur=" + mCurrentIdler + " size=" + mIdleServiceQueue.size());
+        }
+    }
+
     private long getNextIdleMaintenanceIntervalStartFromNow() {
         return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS
                 - SystemClock.elapsedRealtime();
     }
 
-    private void sendIdleMaintenanceStartIntent() {
-        mWakeLock.acquire();
-        try {
-            ActivityManagerNative.getDefault().performIdleMaintenance();
-        } catch (RemoteException e) {
-        }
-        mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL,
-                null, this, mHandler, Activity.RESULT_OK, null, null);
-    }
-
-    private void sendIdleMaintenanceEndIntent() {
-        mWakeLock.acquire();
-        mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceEndIntent, UserHandle.ALL,
-                null, this, mHandler, Activity.RESULT_OK, null, null);
-    }
-
     private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) {
         final int minBatteryLevel = isBatteryCharging()
                 ? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
@@ -281,7 +777,7 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         if (DEBUG) {
-            Log.i(LOG_TAG, intent.getAction());
+            Log.i(TAG, intent.getAction());
         }
         String action = intent.getAction();
         if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
@@ -292,7 +788,7 @@
             // next release. The only client for this for now is internal an holds
             // a wake lock correctly.
             if (mIdleMaintenanceStarted) {
-                updateIdleMaintenanceState(false);
+                updateIdleMaintenanceStateTm(false);
             }
         } else if (Intent.ACTION_SCREEN_ON.equals(action)
                 || Intent.ACTION_DREAMING_STOPPED.equals(action)) {
@@ -302,7 +798,7 @@
             unscheduleUpdateIdleMaintenanceState();
             // If the screen went on/stopped dreaming, we know the user is using the
             // device which means that idle maintenance should be stopped if running.
-            updateIdleMaintenanceState(false);
+            updateIdleMaintenanceStateTm(false);
         } else if (Intent.ACTION_SCREEN_OFF.equals(action)
                 || Intent.ACTION_DREAMING_STARTED.equals(action)) {
             mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
@@ -311,17 +807,12 @@
             // this timeout elapses since the device may go to sleep by then.
             scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
         } else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) {
-            updateIdleMaintenanceState(false);
+            updateIdleMaintenanceStateTm(false);
         } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) {
             long now = SystemClock.elapsedRealtime() - 1;
             mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START;
             mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
-            updateIdleMaintenanceState(true);
-        } else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)
-                || Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
-            // We were holding a wake lock while broadcasting the idle maintenance
-            // intents but now that we finished the broadcast release the wake lock.
-            mWakeLock.release();
+            updateIdleMaintenanceStateTm(true);
         }
     }
 }
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 816ae69..e6e4bca 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -107,6 +107,9 @@
 class MountService extends IMountService.Stub
         implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
 
+    // Static direct instance pointer for the tightly-coupled idle service to use
+    static MountService sSelf = null;
+
     // TODO: listen for user creation/deletion
 
     private static final boolean LOCAL_LOGD = false;
@@ -345,6 +348,7 @@
     private static final int H_UNMOUNT_PM_DONE = 2;
     private static final int H_UNMOUNT_MS = 3;
     private static final int H_SYSTEM_READY = 4;
+    private static final int H_FSTRIM = 5;
 
     private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
     private static final int MAX_UNMOUNT_RETRIES = 4;
@@ -494,6 +498,24 @@
                     }
                     break;
                 }
+                case H_FSTRIM: {
+                    waitForReady();
+                    Slog.i(TAG, "Running fstrim idle maintenance");
+                    try {
+                        // This method must be run on the main (handler) thread,
+                        // so it is safe to directly call into vold.
+                        mConnector.execute("fstrim", "dotrim");
+                        EventLogTags.writeFstrimStart(SystemClock.elapsedRealtime());
+                    } catch (NativeDaemonConnectorException ndce) {
+                        Slog.e(TAG, "Failed to run fstrim!");
+                    }
+                    // invoke the completion callback, if any
+                    Runnable callback = (Runnable) msg.obj;
+                    if (callback != null) {
+                        callback.run();
+                    }
+                    break;
+                }
             }
         }
     };
@@ -608,27 +630,6 @@
         }
     };
 
-    private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            waitForReady();
-            String action = intent.getAction();
-            // Since fstrim will be run on a daily basis we do not expect
-            // fstrim to be too long, so it is not interruptible. We will
-            // implement interruption only in case we see issues.
-            if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) {
-                try {
-                    // This method runs on the handler thread,
-                    // so it is safe to directly call into vold.
-                    mConnector.execute("fstrim", "dotrim");
-                    EventLogTags.writeFstrimStart(SystemClock.elapsedRealtime());
-                } catch (NativeDaemonConnectorException ndce) {
-                    Slog.e(TAG, "Failed to run fstrim!");
-                }
-            }
-        }
-    };
-
     private final class MountServiceBinderListener implements IBinder.DeathRecipient {
         final IMountServiceListener mListener;
 
@@ -646,6 +647,10 @@
         }
     }
 
+    void runIdleMaintenance(Runnable callback) {
+        mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
+    }
+
     private void doShareUnshareVolume(String path, String method, boolean enable) {
         // TODO: Add support for multiple share methods
         if (!method.equals("ums")) {
@@ -1337,6 +1342,8 @@
      * @param context  Binder context for this service
      */
     public MountService(Context context) {
+        sSelf = this;
+
         mContext = context;
 
         synchronized (mVolumesLock) {
@@ -1363,12 +1370,6 @@
                     mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler);
         }
 
-        // Watch for idle maintenance changes
-        IntentFilter idleMaintenanceFilter = new IntentFilter();
-        idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
-        mContext.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL,
-                idleMaintenanceFilter, null, mHandler);
-
         // Add OBB Action Handler to MountService thread.
         mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
 
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
new file mode 100644
index 0000000..8b19321
--- /dev/null
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.maintenance.IdleService;
+import android.util.Slog;
+
+public class MountServiceIdler extends IdleService {
+    private static final String TAG = "MountServiceIdler";
+
+    private Runnable mFinishCallback = new Runnable() {
+        @Override
+        public void run() {
+            Slog.i(TAG, "Got mount service completion callback");
+            finishIdle();
+        }
+    };
+
+    @Override
+    public boolean onIdleStart() {
+        // The mount service will run an fstrim operation asynchronously
+        // on a designated separate thread, so we provide it with a callback
+        // that lets us cleanly end our idle timeslice.  It's safe to call
+        // finishIdle() from any thread.
+        MountService ms = MountService.sSelf;
+        if (ms != null) {
+            ms.runIdleMaintenance(mFinishCallback);
+        }
+        return ms != null;
+    }
+
+    @Override
+    public void onIdleStop() {
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a21157f..8693c31 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3125,7 +3125,7 @@
             }
         }
         int ret = pir.sendInner(0, fillInIntent, resolvedType, null, null,
-                resultTo, resultWho, requestCode, flagsMask, flagsValues, options);
+                resultTo, resultWho, requestCode, flagsMask, flagsValues, options, null);
         return ret;
     }
 
@@ -3237,7 +3237,8 @@
 
     final int startActivityInPackage(int uid, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
-            String resultWho, int requestCode, int startFlags, Bundle options, int userId) {
+            String resultWho, int requestCode, int startFlags, Bundle options, int userId,
+                    IActivityContainer container) {
 
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityInPackage", null);
@@ -3245,7 +3246,7 @@
         // TODO: Switch to user app stacks here.
         int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags,
-                null, null, null, null, options, userId, null);
+                null, null, null, null, options, userId, container);
         return ret;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 70d85fc..4a07256 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -738,6 +738,12 @@
             mStackSupervisor.resumeTopActivitiesLocked();
             return;
         }
+
+        if (mActivityContainer.mParentActivity == null) {
+            // Top level stack, not a child. Look for child stacks.
+            mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping);
+        }
+
         if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
         else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
         mResumedActivity = null;
@@ -1282,6 +1288,13 @@
     final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
         if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
 
+        ActivityRecord parent = mActivityContainer.mParentActivity;
+        if (parent != null && parent.state != ActivityState.RESUMED) {
+            // Do not resume this stack if its parent is not resumed.
+            // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
+            return false;
+        }
+
         cancelInitializingActivities();
 
         // Find the first activity that is not finishing.
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 6115f06..a33b0e5 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -277,6 +277,10 @@
     // TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the
     // top of all visible stacks.
     boolean isFrontStack(ActivityStack stack) {
+        final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
+        if (parent != null) {
+            stack = parent.task.stack;
+        }
         ArrayList<ActivityStack> stacks = stack.mStacks;
         if (stacks != null && !stacks.isEmpty()) {
             return stack == stacks.get(stacks.size() - 1);
@@ -510,6 +514,20 @@
         return pausing;
     }
 
+    void pauseChildStacks(ActivityRecord parent, boolean userLeaving, boolean uiSleeping) {
+		// TODO: Put all stacks in supervisor and iterate through them instead.
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (stack.mResumedActivity != null &&
+                        stack.mActivityContainer.mParentActivity == parent) {
+                    stack.startPausingLocked(userLeaving, uiSleeping);
+                }
+            }
+        }
+    }
+
     void reportActivityVisibleLocked(ActivityRecord r) {
         for (int i = mWaitingActivityVisible.size()-1; i >= 0; i--) {
             WaitResult w = mWaitingActivityVisible.get(i);
@@ -2915,7 +2933,7 @@
             mStack.mStacks = activityDisplay.mStacks;
 
             activityDisplay.attachActivities(mStack);
-            mWindowManager.createStack(mStackId, activityDisplay.mDisplayId);
+            mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId);
         }
 
         @Override
@@ -2945,6 +2963,7 @@
                 mActivityDisplay = null;
                 mStack.mDisplayId = -1;
                 mStack.mStacks = null;
+                mWindowManager.detachStack(mStackId);
             }
         }
 
@@ -2957,7 +2976,7 @@
 
         @Override
         public final int startActivity(Intent intent) {
-            mService.enforceNotIsolatedCaller("ActivityContainer");
+            mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
             int userId = mService.handleIncomingUser(Binder.getCallingPid(),
                     Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null);
             // TODO: Switch to user app stacks here.
@@ -2971,20 +2990,40 @@
         }
 
         @Override
+        public final int startActivityIntentSender(IIntentSender intentSender) {
+            mService.enforceNotIsolatedCaller("ActivityContainer.startActivityIntentSender");
+
+            if (!(intentSender instanceof PendingIntentRecord)) {
+                throw new IllegalArgumentException("Bad PendingIntent object");
+            }
+
+            return ((PendingIntentRecord)intentSender).sendInner(0, null, null, null, null, null,
+                    null, 0, 0, 0, null, this);
+        }
+
+        @Override
         public IBinder asBinder() {
             return this;
         }
 
         @Override
         public void attachToSurface(Surface surface, int width, int height, int density) {
-            synchronized (mService) {
-                ActivityDisplay activityDisplay =
-                        new ActivityDisplay(surface, width, height, density);
-                mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay);
-                attachToDisplayLocked(activityDisplay);
+            mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface");
+
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                synchronized (mService) {
+                    ActivityDisplay activityDisplay =
+                            new ActivityDisplay(surface, width, height, density);
+                    mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay);
+                    attachToDisplayLocked(activityDisplay);
+                    mStack.resumeTopActivityLocked(null);
+                }
+                if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display="
+                        + mActivityDisplay);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
             }
-            if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display="
-                    + mActivityDisplay);
         }
 
         ActivityStackSupervisor getOuter() {
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 17f24a9..00fa216 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.app.ActivityManager;
+import android.app.IActivityContainer;
 import android.content.IIntentSender;
 import android.content.IIntentReceiver;
 import android.app.PendingIntent;
@@ -190,13 +191,13 @@
     public int send(int code, Intent intent, String resolvedType,
             IIntentReceiver finishedReceiver, String requiredPermission) {
         return sendInner(code, intent, resolvedType, finishedReceiver,
-                requiredPermission, null, null, 0, 0, 0, null);
+                requiredPermission, null, null, 0, 0, 0, null, null);
     }
     
     int sendInner(int code, Intent intent, String resolvedType,
             IIntentReceiver finishedReceiver, String requiredPermission,
             IBinder resultTo, String resultWho, int requestCode,
-            int flagsMask, int flagsValues, Bundle options) {
+            int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {
         synchronized(owner) {
             if (!canceled) {
                 sent = true;
@@ -251,7 +252,7 @@
                             } else {
                                 owner.startActivityInPackage(uid, key.packageName, finalIntent,
                                         resolvedType, resultTo, resultWho, requestCode, 0,
-                                        options, userId);
+                                        options, userId, container);
                             }
                         } catch (RuntimeException e) {
                             Slog.w(ActivityManagerService.TAG,
@@ -302,7 +303,8 @@
         }
         return ActivityManager.START_CANCELED;
     }
-    
+
+    @Override
     protected void finalize() throws Throwable {
         try {
             if (!canceled) {
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 978d5b7..30eaf45 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -51,9 +51,9 @@
     /** Owning stack */
     final TaskStack mStack;
 
-    DimLayer(WindowManagerService service, TaskStack stack) {
+    DimLayer(WindowManagerService service, TaskStack stack, DisplayContent displayContent) {
         mStack = stack;
-        mDisplayContent = stack.getDisplayContent();
+        mDisplayContent = displayContent;
         final int displayId = mDisplayContent.getDisplayId();
         if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
         SurfaceControl.openTransaction();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0a070c1..9f45e88 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerService.TAG;
 
@@ -116,7 +115,7 @@
 
     /**
      * @param display May not be null.
-     * @param service TODO(cmautner):
+     * @param service You know.
      */
     DisplayContent(Display display, WindowManagerService service) {
         mDisplay = display;
@@ -236,19 +235,16 @@
         return count;
     }
 
-    /** Refer to {@link WindowManagerService#createStack(int, int)} */
-    TaskStack createStack(int stackId) {
-        if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId);
-        TaskStack newStack = new TaskStack(mService, stackId, this);
-        if (stackId == HOME_STACK_ID) {
+    /** Refer to {@link WindowManagerService#attachStack(int, int)} */
+    void attachStack(TaskStack stack) {
+        if (stack.mStackId == HOME_STACK_ID) {
             if (mHomeStack != null) {
-                throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
+                throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
             }
-            mHomeStack = newStack;
+            mHomeStack = stack;
         }
-        mStacks.add(newStack);
+        mStacks.add(stack);
         layoutNeeded = true;
-        return newStack;
     }
 
     void moveStack(TaskStack stack, boolean toTop) {
@@ -256,12 +252,15 @@
         mStacks.add(toTop ? mStacks.size() : 0, stack);
     }
 
-    TaskStack removeStack(TaskStack stack) {
-        mStacks.remove(stack);
-        if (!mStacks.isEmpty()) {
-            return mStacks.get(mStacks.size() - 1);
+    void detachStack(TaskStack stack) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mTaskHistory.get(taskNdx);
+            if (task.mStack == stack) {
+                mService.tmpRemoveTaskWindowsLocked(task);
+                mTaskHistory.remove(taskNdx);
+            }
         }
-        return null;
+        mStacks.remove(stack);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 87cabc9..ca9076f 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -293,7 +293,11 @@
             // !!! FIXME: put all this heavy stuff onto the mH looper, as well as
             // the actual drag event dispatch stuff in the dragstate
 
-            Display display = callingWin.mDisplayContent.getDisplay();
+            final DisplayContent displayContent = callingWin.getDisplayContent();
+            if (displayContent == null) {
+               return false;
+            }
+            Display display = displayContent.getDisplay();
             mService.mDragState.register(display);
             mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
             if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a1704a6..44f2596 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -45,7 +45,6 @@
         if (mAppTokens.size() == 0) {
             EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId,
                     "removeAppToken: last token");
-            mStack.removeTask(this);
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index aa6b0c9..1ada6c2 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -41,7 +41,7 @@
     private final WindowManagerService mService;
 
     /** The display this stack sits under. */
-    private final DisplayContent mDisplayContent;
+    private DisplayContent mDisplayContent;
 
     /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
      * mTaskHistory in the ActivityStack with the same mStackId */
@@ -52,13 +52,13 @@
     Rect mBounds = new Rect();
 
     /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
-    final DimLayer mDimLayer;
+    DimLayer mDimLayer;
 
     /** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */
     WindowStateAnimator mDimWinAnimator;
 
     /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
-    final DimLayer mAnimationBackgroundSurface;
+    DimLayer mAnimationBackgroundSurface;
 
     /** The particular window with an Animation with non-zero background color. */
     WindowStateAnimator mAnimationBackgroundAnimator;
@@ -67,12 +67,9 @@
      * then stop any dimming. */
     boolean mDimmingTag;
 
-    TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent) {
+    TaskStack(WindowManagerService service, int stackId) {
         mService = service;
         mStackId = stackId;
-        mDisplayContent = displayContent;
-        mDimLayer = new DimLayer(service, this);
-        mAnimationBackgroundSurface = new DimLayer(service, this);
         // TODO: remove bounds from log, they are always 0.
         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top,
                 mBounds.right, mBounds.bottom);
@@ -121,12 +118,16 @@
     }
 
     void getBounds(Rect out) {
-        if (mBounds.isEmpty()) {
-            mDisplayContent.getLogicalDisplayRect(out);
+        if (mDisplayContent != null) {
+            if (mBounds.isEmpty()) {
+                mDisplayContent.getLogicalDisplayRect(out);
+            } else {
+                out.set(mBounds);
+            }
+            out.intersect(mDisplayContent.mContentRect);
         } else {
             out.set(mBounds);
         }
-        out.intersect(mDisplayContent.mContentRect);
     }
 
     boolean isFullscreen() {
@@ -198,22 +199,37 @@
     void removeTask(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
         mTasks.remove(task);
-        mDisplayContent.removeTask(task);
-        if (mTasks.isEmpty()) {
-            mDisplayContent.moveStack(this, false);
+        if (mDisplayContent != null) {
+            mDisplayContent.removeTask(task);
+            if (mTasks.isEmpty()) {
+                mDisplayContent.moveStack(this, false);
+            }
+            mDisplayContent.layoutNeeded = true;
         }
-        mDisplayContent.layoutNeeded = true;
     }
 
-    int remove() {
-        mAnimationBackgroundSurface.destroySurface();
-        mDimLayer.destroySurface();
-        EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
-        TaskStack next = mDisplayContent.removeStack(this);
-        if (next != null) {
-            return next.mStackId;
+    void attachDisplayContent(DisplayContent displayContent) {
+        if (mDisplayContent != null) {
+            throw new IllegalStateException("attachDisplayContent: Already attached");
         }
-        return -1;
+
+        mDisplayContent = displayContent;
+        mDimLayer = new DimLayer(mService, this, displayContent);
+        mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent);
+
+        for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
+            Task task = mTasks.get(taskNdx);
+            displayContent.addTask(task, true);
+        }
+    }
+
+    void detach() {
+        EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
+        mAnimationBackgroundSurface.destroySurface();
+        mAnimationBackgroundSurface = null;
+        mDimLayer.destroySurface();
+        mDimLayer = null;
+        mDisplayContent = null;
     }
 
     void resetAnimationBackgroundAnimator() {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 91f15f3..b4285c6 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -642,11 +642,16 @@
     }
 
     int getPendingLayoutChanges(final int displayId) {
+        if (displayId < 0) {
+            return 0;
+        }
         return mService.getDisplayContentLocked(displayId).pendingLayoutChanges;
     }
 
     void setPendingLayoutChanges(final int displayId, final int changes) {
-        mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
+        if (displayId >= 0) {
+            mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
+        }
     }
 
     void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
@@ -655,7 +660,7 @@
         WindowList windows = appAnimator.mAppToken.allAppWindows;
         for (int i = windows.size() - 1; i >= 0; i--) {
             final int displayId = windows.get(i).getDisplayId();
-            if (displays.indexOfKey(displayId) < 0) {
+            if (displayId >= 0 && displays.indexOfKey(displayId) < 0) {
                 setPendingLayoutChanges(displayId, changes);
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                     mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId));
@@ -676,10 +681,15 @@
     }
 
     void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
-        getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+        if (displayId >= 0) {
+            getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+        }
     }
 
     ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
+        if (displayId < 0) {
+            return null;
+        }
         return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6c7fb26..5387436 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -155,8 +155,7 @@
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
-        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
-        DisplayManager.DisplayListener {
+        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
@@ -269,10 +268,10 @@
     // Default input dispatching timeout in nanoseconds.
     static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
 
-    /** Minimum value for createStack and resizeStack weight value */
+    /** Minimum value for attachStack and resizeStack weight value */
     public static final float STACK_WEIGHT_MIN = 0.2f;
 
-    /** Maximum value for createStack and resizeStack weight value */
+    /** Maximum value for attachStack and resizeStack weight value */
     public static final float STACK_WEIGHT_MAX = 0.8f;
 
     static final int UPDATE_FOCUS_NORMAL = 0;
@@ -742,7 +741,6 @@
 
         mFxSession = new SurfaceSession();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
-        mDisplayManager.registerDisplayListener(this, null);
         Display[] displays = mDisplayManager.getDisplays();
         for (Display display : displays) {
             createDisplayContentLocked(display);
@@ -874,7 +872,7 @@
         final int count = token.windows.size();
         for (int i = 0; i < count; i++) {
             final WindowState win = token.windows.get(i);
-            if (win.mDisplayContent == displayContent) {
+            if (win.getDisplayContent() == displayContent) {
                 windowList.add(win);
             }
         }
@@ -905,7 +903,7 @@
     private int addAppWindowToListLocked(final WindowState win) {
         final IWindow client = win.mClient;
         final WindowToken token = win.mToken;
-        final DisplayContent displayContent = win.mDisplayContent;
+        final DisplayContent displayContent = win.getDisplayContent();
 
         final WindowList windows = win.getWindowList();
         final int N = windows.size();
@@ -1082,7 +1080,7 @@
 
     private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {
         final WindowToken token = win.mToken;
-        final DisplayContent displayContent = win.mDisplayContent;
+        final DisplayContent displayContent = win.getDisplayContent();
         final WindowState attached = win.mAttachedWindow;
 
         WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
@@ -2016,7 +2014,10 @@
     }
 
     void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
-        final DisplayContent displayContent = changingTarget.mDisplayContent;
+        final DisplayContent displayContent = changingTarget.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
@@ -2076,7 +2077,10 @@
 
     void updateWallpaperVisibilityLocked() {
         final boolean visible = isWallpaperVisible(mWallpaperTarget);
-        final DisplayContent displayContent = mWallpaperTarget.mDisplayContent;
+        final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
@@ -2428,7 +2432,10 @@
                 //Slog.i(TAG, "*** Running exit animation...");
                 win.mExiting = true;
                 win.mRemoveOnExit = true;
-                win.mDisplayContent.layoutNeeded = true;
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (displayContent != null) {
+                    displayContent.layoutNeeded = true;
+                }
                 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                         false /*updateInputWindows*/);
                 performLayoutAndPlaceSurfacesLocked();
@@ -2485,8 +2492,6 @@
             mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
         }
 
-        final WindowList windows = win.getWindowList();
-        windows.remove(win);
         mPendingRemove.remove(win);
         mResizingWindows.remove(win);
         mWindowsChanged = true;
@@ -2541,12 +2546,19 @@
                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
         }
 
-        if (!mInLayout) {
-            assignLayersLocked(windows);
-            win.mDisplayContent.layoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
-            if (win.mAppToken != null) {
-                win.mAppToken.updateReportedVisibilityLocked();
+        final WindowList windows = win.getWindowList();
+        if (windows != null) {
+            windows.remove(win);
+            if (!mInLayout) {
+                assignLayersLocked(windows);
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (displayContent != null) {
+                    displayContent.layoutNeeded = true;
+                }
+                performLayoutAndPlaceSurfacesLocked();
+                if (win.mAppToken != null) {
+                    win.mAppToken.updateReportedVisibilityLocked();
+                }
             }
         }
 
@@ -2621,7 +2633,10 @@
                         w.mGivenVisibleInsets.scale(w.mGlobalScale);
                         w.mGivenTouchableRegion.scale(w.mGlobalScale);
                     }
-                    w.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = w.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                     performLayoutAndPlaceSurfacesLocked();
                 }
             }
@@ -2707,7 +2722,12 @@
         mTmpFloats[Matrix.MSKEW_X] = dsdy;
         mTmpFloats[Matrix.MSCALE_Y] = dtdy;
         matrix.setValues(mTmpFloats);
-        final DisplayInfo displayInfo = window.mDisplayContent.getDisplayInfo();
+        final DisplayContent displayContent = window.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
+
+        final DisplayInfo displayInfo = window.getDisplayContent().getDisplayInfo();
         final RectF dispRect = new RectF(0, 0,
                 displayInfo.logicalWidth, displayInfo.logicalHeight);
         matrix.mapRect(dispRect);
@@ -2716,7 +2736,7 @@
         window.mGivenTouchableRegion.op((int)dispRect.left, (int)dispRect.top,
                 (int)dispRect.right, (int)dispRect.bottom, Region.Op.DIFFERENCE);
         window.mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-        window.mDisplayContent.layoutNeeded = true;
+        displayContent.layoutNeeded = true;
         performLayoutAndPlaceSurfacesLocked();
     }
 
@@ -2997,7 +3017,10 @@
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
             }
 
-            win.mDisplayContent.layoutNeeded = true;
+            final DisplayContent displayContent = win.getDisplayContent();
+            if (displayContent != null) {
+                displayContent.layoutNeeded = true;
+            }
             win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             configChanged = updateOrientationFromAppTokensLocked(false);
             performLayoutAndPlaceSurfacesLocked();
@@ -3091,7 +3114,10 @@
                         getDefaultDisplayContentLocked().pendingLayoutChanges |=
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                     }
-                    win.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = win.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                     requestTraversalLocked();
                 }
             }
@@ -3349,7 +3375,7 @@
 
                     for (int i=0; i<N; i++) {
                         WindowState win = wtoken.windows.get(i);
-                        displayContent = win.mDisplayContent;
+                        displayContent = win.getDisplayContent();
 
                         if (win.mWinAnimator.isAnimating()) {
                             delayed = true;
@@ -3364,7 +3390,9 @@
                                         WindowManagerPolicy.TRANSIT_EXIT);
                             }
                             changed = true;
-                            displayContent.layoutNeeded = true;
+                            if (displayContent != null) {
+                                displayContent.layoutNeeded = true;
+                            }
                         }
                     }
 
@@ -3377,7 +3405,9 @@
                     }
 
                     if (delayed) {
-                        displayContent.mExitingTokens.add(wtoken);
+                        if (displayContent != null) {
+                            displayContent.mExitingTokens.add(wtoken);
+                        }
                     } else if (wtoken.windowType == TYPE_WALLPAPER) {
                         mWallpaperTokens.remove(wtoken);
                     }
@@ -3473,8 +3503,8 @@
                 Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
                 return;
             }
-            Task oldTask = mTaskIdToTask.get(atoken.groupId);
-            oldTask.removeAppToken(atoken);
+            final Task oldTask = mTaskIdToTask.get(atoken.groupId);
+            removeAppFromTask(atoken);
 
             atoken.groupId = groupId;
             Task newTask = mTaskIdToTask.get(groupId);
@@ -3767,7 +3797,10 @@
         if (mFocusedApp != null) {
             Task task = mTaskIdToTask.get(mFocusedApp.groupId);
             stack = task.mStack;
-            task.getDisplayContent().setTouchExcludeRegion(stack);
+            final DisplayContent displayContent = task.getDisplayContent();
+            if (displayContent != null) {
+                displayContent.setTouchExcludeRegion(stack);
+            }
         } else {
             stack = null;
         }
@@ -4224,7 +4257,10 @@
                             }
                         }
                         changed = true;
-                        win.mDisplayContent.layoutNeeded = true;
+                        final DisplayContent displayContent = win.getDisplayContent();
+                        if (displayContent != null) {
+                            displayContent.layoutNeeded = true;
+                        }
                     }
                 } else if (win.isVisibleNow()) {
                     if (!runningAppAnimation) {
@@ -4238,7 +4274,10 @@
                         }
                     }
                     changed = true;
-                    win.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = win.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                 }
             }
 
@@ -4386,7 +4425,10 @@
                     }
                     w.mLastFreezeDuration = 0;
                     unfrozeWindows = true;
-                    w.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = w.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                 }
             }
             if (force || unfrozeWindows) {
@@ -4480,6 +4522,14 @@
         }
     }
 
+    void removeAppFromTask(AppWindowToken wtoken) {
+        final Task task = mTaskIdToTask.get(wtoken.groupId);
+        if (task != null && task.removeAppToken(wtoken)) {
+            task.mStack.removeTask(task);
+            mTaskIdToTask.delete(wtoken.groupId);
+        }
+    }
+
     @Override
     public void removeAppToken(IBinder token) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4514,7 +4564,7 @@
                         + " animating=" + wtoken.mAppAnimator.animating);
                 final Task task = mTaskIdToTask.get(wtoken.groupId);
                 DisplayContent displayContent = task.getDisplayContent();
-                if (delayed) {
+                if (displayContent != null && delayed) {
                     // set the token aside because it has an active animation to be finished
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "removeAppToken make exiting: " + wtoken);
@@ -4529,9 +4579,8 @@
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
 
-                if (task.removeAppToken(wtoken)) {
-                    mTaskIdToTask.delete(wtoken.groupId);
-                }
+                removeAppFromTask(wtoken);
+
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
                     startingToken = wtoken;
@@ -4566,13 +4615,15 @@
             mH.sendMessage(m);
         }
     }
+
     private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
-        final int NW = token.windows.size();
+        WindowList windows = token.windows;
+        final int NW = windows.size();
         if (NW > 0) {
             mWindowsChanged = true;
         }
-        for (int i=0; i<NW; i++) {
-            WindowState win = token.windows.get(i);
+        for (int i = 0; i < NW; i++) {
+            WindowState win = windows.get(i);
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
             win.getWindowList().remove(win);
             int j = win.mChildWindows.size();
@@ -4605,12 +4656,13 @@
     }
 
     void dumpWindowsLocked() {
-        int i = 0;
         final int numDisplays = mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+            Slog.v(TAG, " Display #" + displayContent.getDisplayId());
+            final WindowList windows = displayContent.getWindowList();
             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                Slog.v(TAG, "  #" + i++ + ": " + windows.get(winNdx));
+                Slog.v(TAG, "  #" + winNdx + ": " + windows.get(winNdx));
             }
         }
     }
@@ -4722,23 +4774,28 @@
         final int NW = token.windows.size();
         for (int i=0; i<NW; i++) {
             final WindowState win = token.windows.get(i);
-            if (win.mDisplayContent == displayContent) {
+            final DisplayContent winDisplayContent = win.getDisplayContent();
+            if (winDisplayContent == displayContent || winDisplayContent == null) {
+                win.mDisplayContent = displayContent;
                 index = reAddWindowLocked(index, win);
             }
         }
         return index;
     }
 
+    void tmpRemoveTaskWindowsLocked(Task task) {
+        AppTokenList tokens = task.mAppTokens;
+        for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+            tmpRemoveAppWindowsLocked(tokens.get(tokenNdx));
+        }
+    }
+
     void moveStackWindowsLocked(DisplayContent displayContent) {
         // First remove all of the windows from the list.
         final ArrayList<Task> tasks = displayContent.getTasks();
         final int numTasks = tasks.size();
         for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = numTokens - 1; tokenNdx >= 0; --tokenNdx) {
-                tmpRemoveAppWindowsLocked(tokens.get(tokenNdx));
-            }
+            tmpRemoveTaskWindowsLocked(tasks.get(taskNdx));
         }
 
         // And now add them back at the correct place.
@@ -4822,15 +4879,25 @@
      * @param stackId The unique identifier of the new stack.
      * @param displayId The unique identifier of the DisplayContent.
      */
-    public void createStack(int stackId, int displayId) {
+    public void attachStack(int stackId, int displayId) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
                 final DisplayContent displayContent = mDisplayContents.get(displayId);
                 if (displayContent != null) {
-                    TaskStack stack = displayContent.createStack(stackId);
-                    mStackIdToStack.put(stackId, stack);
-                    performLayoutAndPlaceSurfacesLocked();
+                    TaskStack stack = mStackIdToStack.get(stackId);
+                    if (stack == null) {
+                        if (DEBUG_STACK) Slog.d(TAG, "attachStack: stackId=" + stackId);
+                        stack = new TaskStack(this, stackId);
+                        mStackIdToStack.put(stackId, stack);
+                    }
+                    stack.attachDisplayContent(displayContent);
+                    displayContent.attachStack(stack);
+                    moveStackWindowsLocked(displayContent);
+                    final WindowList windows = displayContent.getWindowList();
+                    for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                        windows.get(winNdx).reportResized();
+                    }
                 }
             }
         } finally {
@@ -4838,6 +4905,19 @@
         }
     }
 
+    public void detachStack(int stackId) {
+        synchronized (mWindowMap) {
+            TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack != null) {
+                final DisplayContent displayContent = stack.getDisplayContent();
+                if (displayContent != null) {
+                    displayContent.detachStack(stack);
+                    stack.detach();
+                }
+            }
+        }
+    }
+
     public void removeTask(int taskId) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -7888,7 +7968,6 @@
     }
 
     final void rebuildAppWindowListLocked() {
-        // TODO: Multidisplay, when ActivityStacks and tasks exist on more than one display.
         rebuildAppWindowListLocked(getDefaultDisplayContentLocked());
     }
 
@@ -7953,7 +8032,8 @@
 
         i -= lastBelow;
         if (i != numRemoved) {
-            Slog.w(TAG, "Rebuild removed " + numRemoved + " windows but added " + i,
+            Slog.w(TAG, "On display=" + displayContent.getDisplayId() + " Rebuild removed " +
+                    numRemoved + " windows but added " + i,
                     new RuntimeException("here").fillInStackTrace());
             for (i=0; i<numRemoved; i++) {
                 WindowState ws = mRebuildTmp[i];
@@ -8763,8 +8843,8 @@
             if (canBeSeen) {
                 // This function assumes that the contents of the default display are
                 // processed first before secondary displays.
-                final DisplayContent displayContent = w.mDisplayContent;
-                if (displayContent.isDefaultDisplay) {
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && displayContent.isDefaultDisplay) {
                     // While a dream or keyguard is showing, obscure ordinary application
                     // content on secondary displays (by forcibly enabling mirroring unless
                     // there is other content we want to show) but still allow opaque
@@ -8773,8 +8853,9 @@
                         mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
                     }
                     mInnerFields.mDisplayHasContent = true;
-                } else if (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
-                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG)) {
+                } else if (displayContent != null &&
+                        (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
+                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG))) {
                     // Allow full screen keyguard presentation dialogs to be seen.
                     mInnerFields.mDisplayHasContent = true;
                 }
@@ -9199,56 +9280,22 @@
                 continue;
             }
             final WindowStateAnimator winAnimator = win.mWinAnimator;
-            try {
-                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
-                        "Reporting new frame to " + win + ": " + win.mCompatFrame);
-                int diff = 0;
-                boolean configChanged = win.isConfigChanged();
-                if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
-                        && configChanged) {
-                    Slog.i(TAG, "Sending new config to window " + win + ": "
-                            + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
-                            + " / " + mCurConfiguration + " / 0x"
-                            + Integer.toHexString(diff));
-                }
-                win.setConfiguration(mCurConfiguration);
-                if (DEBUG_ORIENTATION &&
-                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
-                        TAG, "Resizing " + win + " WITH DRAW PENDING");
-                final IWindow client = win.mClient;
-                final Rect frame = win.mFrame;
-                final Rect overscanInsets = win.mLastOverscanInsets;
-                final Rect contentInsets = win.mLastContentInsets;
-                final Rect visibleInsets = win.mLastVisibleInsets;
-                final boolean reportDraw
-                        = winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
-                final Configuration newConfig = configChanged ? win.mConfiguration : null;
-                if (win.mClient instanceof IWindow.Stub) {
-                    // To prevent deadlock simulate one-way call if win.mClient is a local object.
-                    mH.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            try {
-                                client.resized(frame, overscanInsets, contentInsets,
-                                        visibleInsets, reportDraw, newConfig);
-                            } catch (RemoteException e) {
-                                // Not a remote call, RemoteException won't be raised.
-                            }
-                        }
-                    });
-                } else {
-                   client.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
-                           newConfig);
-                }
-                win.mOverscanInsetsChanged = false;
-                win.mContentInsetsChanged = false;
-                win.mVisibleInsetsChanged = false;
-                winAnimator.mSurfaceResized = false;
-            } catch (RemoteException e) {
-                win.mOrientationChanging = false;
-                win.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
-                        - mDisplayFreezeTime);
+            if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
+                    "Reporting new frame to " + win + ": " + win.mCompatFrame);
+            int diff = 0;
+            boolean configChanged = win.isConfigChanged();
+            if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
+                    && configChanged) {
+                Slog.i(TAG, "Sending new config to window " + win + ": "
+                        + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
+                        + " / " + mCurConfiguration + " / 0x"
+                        + Integer.toHexString(diff));
             }
+            win.setConfiguration(mCurConfiguration);
+            if (DEBUG_ORIENTATION &&
+                    winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
+                    TAG, "Resizing " + win + " WITH DRAW PENDING");
+            win.reportResized();
             mResizingWindows.remove(i);
         }
 
@@ -9309,10 +9356,7 @@
                     token.mAppAnimator.animating = false;
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "performLayout: App token exiting now removed" + token);
-                    final Task task = mTaskIdToTask.get(token.groupId);
-                    if (task != null && task.removeAppToken(token)) {
-                        mTaskIdToTask.delete(token.groupId);
-                    }
+                    removeAppFromTask(token);
                     exitingAppTokens.remove(i);
                 }
             }
@@ -9393,8 +9437,9 @@
             for (i = 0; i < N; i++) {
                 WindowState w = mPendingRemoveTmp[i];
                 removeWindowInnerLocked(w.mSession, w);
-                if (!displayList.contains(w.mDisplayContent)) {
-                    displayList.add(w.mDisplayContent);
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && !displayList.contains(displayContent)) {
+                    displayList.add(displayContent);
                 }
             }
 
@@ -10765,7 +10810,6 @@
         return displayContent != null ? displayContent.getWindowList() : null;
     }
 
-    @Override
     public void onDisplayAdded(int displayId) {
         mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
     }
@@ -10780,7 +10824,6 @@
         }
     }
 
-    @Override
     public void onDisplayRemoved(int displayId) {
         mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
     }
@@ -10793,16 +10836,10 @@
             if (displayId == Display.DEFAULT_DISPLAY) {
                 unregisterPointerEventListener(displayContent.mTapDetector);
             }
-            WindowList windows = displayContent.getWindowList();
-            while (!windows.isEmpty()) {
-                final WindowState win = windows.get(windows.size() - 1);
-                removeWindowLocked(win.mSession, win);
-            }
         }
         mAnimator.removeDisplayLocked(displayId);
     }
 
-    @Override
     public void onDisplayChanged(int displayId) {
         mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 77a36b8..2f778b1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -29,7 +29,9 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import android.app.AppOpsManager;
+import android.os.Debug;
 import android.os.RemoteCallbackList;
+import android.os.SystemClock;
 import android.util.TimeUtils;
 import android.view.IWindowFocusObserver;
 import android.view.IWindowId;
@@ -593,9 +595,12 @@
         }
 
         if (mIsWallpaper && (fw != mFrame.width() || fh != mFrame.height())) {
-            final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
-            mService.updateWallpaperOffsetLocked(this,
-                    displayInfo.logicalWidth, displayInfo.logicalHeight, false);
+            final DisplayContent displayContent = getDisplayContent();
+            if (displayContent != null) {
+                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+                mService.updateWallpaperOffsetLocked(this,
+                        displayInfo.logicalWidth, displayInfo.logicalHeight, false);
+            }
         }
 
         if (DEBUG_LAYOUT || WindowManagerService.localLOGV) Slog.v(TAG,
@@ -708,8 +713,16 @@
         return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged;
     }
 
+    public DisplayContent getDisplayContent() {
+        return mAppToken == null ? mDisplayContent : getStack().getDisplayContent();
+    }
+
     public int getDisplayId() {
-        return mDisplayContent.getDisplayId();
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent == null) {
+            return -1;
+        }
+        return displayContent.getDisplayId();
     }
 
     TaskStack getStack() {
@@ -722,7 +735,8 @@
                 }
                 Slog.e(TAG, "getStack: mStack null for task=" + task);
             } else {
-                Slog.e(TAG, "getStack: couldn't find taskId=" + wtoken.groupId);
+                Slog.e(TAG, "getStack: " + this + " couldn't find taskId=" + wtoken.groupId
+                    + " Callers=" + Debug.getCallers(4));
             }
         }
         return mDisplayContent.getHomeStack();
@@ -1196,7 +1210,12 @@
 
     @Override
     public boolean isDefaultDisplay() {
-        return mDisplayContent.isDefaultDisplay;
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent == null) {
+            // Only a window that was on a non-default display can be detached from it.
+            return false;
+        }
+        return getDisplayContent().isDefaultDisplay;
     }
 
     public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
@@ -1213,7 +1232,11 @@
                 && win.mAppToken != null && win.mAppToken.showWhenLocked) {
             // Save some cycles by not calling getDisplayInfo unless it is an application
             // window intended for all users.
-            final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo();
+            final DisplayContent displayContent = win.getDisplayContent();
+            if (displayContent == null) {
+                return true;
+            }
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
             if (win.mFrame.left <= 0 && win.mFrame.top <= 0
                     && win.mFrame.right >= displayInfo.appWidth
                     && win.mFrame.bottom >= displayInfo.appHeight) {
@@ -1255,7 +1278,8 @@
     }
 
     WindowList getWindowList() {
-        return mDisplayContent.getWindowList();
+        final DisplayContent displayContent = getDisplayContent();
+        return displayContent == null ? null : displayContent.getWindowList();
     }
 
     /**
@@ -1284,6 +1308,43 @@
         }
     }
 
+    void reportResized() {
+        try {
+            final Rect frame = mFrame;
+            final Rect overscanInsets = mLastOverscanInsets;
+            final Rect contentInsets = mLastContentInsets;
+            final Rect visibleInsets = mLastVisibleInsets;
+            final boolean reportDraw
+                    = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
+            final Configuration newConfig = isConfigChanged() ? mConfiguration : null;
+            if (mClient instanceof IWindow.Stub) {
+                // To prevent deadlock simulate one-way call if win.mClient is a local object.
+                mService.mH.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            mClient.resized(frame, overscanInsets, contentInsets,
+                                    visibleInsets, reportDraw, newConfig);
+                        } catch (RemoteException e) {
+                            // Not a remote call, RemoteException won't be raised.
+                        }
+                    }
+                });
+            } else {
+                mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
+                        newConfig);
+            }
+            mOverscanInsetsChanged = false;
+            mContentInsetsChanged = false;
+            mVisibleInsetsChanged = false;
+            mWinAnimator.mSurfaceResized = false;
+        } catch (RemoteException e) {
+            mOrientationChanging = false;
+            mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+                    - mService.mDisplayFreezeTime);
+        }
+    }
+
     public void registerFocusObserver(IWindowFocusObserver observer) {
         synchronized(mService.mWindowMap) {
             if (mFocusCallbacks == null) {
@@ -1308,7 +1369,7 @@
     }
 
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
-        pw.print(prefix); pw.print("mDisplayId="); pw.print(mDisplayContent.getDisplayId());
+        pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
                 pw.print(" mSession="); pw.print(mSession);
                 pw.print(" mClient="); pw.println(mClient.asBinder());
         pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c405170..76e885f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -150,8 +150,6 @@
     int mAttrFlags;
     int mAttrType;
 
-    final int mLayerStack;
-
     public WindowStateAnimator(final WindowState win) {
         final WindowManagerService service = win.mService;
 
@@ -159,7 +157,7 @@
         mAnimator = service.mAnimator;
         mPolicy = service.mPolicy;
         mContext = service.mContext;
-        final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo();
+        final DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo();
         mAnimDw = displayInfo.appWidth;
         mAnimDh = displayInfo.appHeight;
 
@@ -171,7 +169,6 @@
         mAttrFlags = win.mAttrs.flags;
         mAttrType = win.mAttrs.type;
         mIsWallpaper = win.mIsWallpaper;
-        mLayerStack = win.mDisplayContent.getDisplay().getLayerStack();
     }
 
     public void setAnimation(Animation anim) {
@@ -243,7 +240,8 @@
         // Save the animation state as it was before this step so WindowManagerService can tell if
         // we just started or just stopped animating by comparing mWasAnimating with isAnimating().
         mWasAnimating = mAnimating;
-        if (mService.okToDisplay()) {
+        final DisplayContent displayContent = mWin.getDisplayContent();
+        if (displayContent != null && mService.okToDisplay()) {
             // We will run animations as long as the display isn't frozen.
 
             if (mWin.isDrawnLw() && mAnimation != null) {
@@ -258,7 +256,7 @@
                         " scale=" + mService.mWindowAnimationScale);
                     mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
                             mAnimDw, mAnimDh);
-                    final DisplayInfo displayInfo = mWin.mDisplayContent.getDisplayInfo();
+                    final DisplayInfo displayInfo = displayContent.getDisplayInfo();
                     mAnimDw = displayInfo.appWidth;
                     mAnimDh = displayInfo.appHeight;
                     mAnimation.setStartTime(currentTime);
@@ -337,7 +335,9 @@
                         + mWin.mPolicyVisibilityAfterAnim);
             }
             mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim;
-            mWin.mDisplayContent.layoutNeeded = true;
+            if (displayContent != null) {
+                displayContent.layoutNeeded = true;
+            }
             if (!mWin.mPolicyVisibility) {
                 if (mService.mCurrentFocus == mWin) {
                     if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
@@ -363,11 +363,13 @@
         } else if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
             // Upon completion of a not-visible to visible status bar animation a relayout is
             // required.
-            mWin.mDisplayContent.layoutNeeded = true;
+            if (displayContent != null) {
+                displayContent.layoutNeeded = true;
+            }
         }
 
         finishExit();
-        final int displayId = mWin.mDisplayContent.getDisplayId();
+        final int displayId = mWin.getDisplayId();
         mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats(
                 "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
@@ -732,7 +734,10 @@
                     mSurfaceY = mWin.mFrame.top + mWin.mYOffset;
                     mSurfaceControl.setPosition(mSurfaceX, mSurfaceY);
                     mSurfaceLayer = mAnimLayer;
-                    mSurfaceControl.setLayerStack(mLayerStack);
+                    final DisplayContent displayContent = mWin.getDisplayContent();
+                    if (displayContent != null) {
+                        mSurfaceControl.setLayerStack(displayContent.getDisplay().getLayerStack());
+                    }
                     mSurfaceControl.setLayer(mAnimLayer);
                     mSurfaceControl.setAlpha(0);
                     mSurfaceShown = false;
@@ -921,8 +926,7 @@
                 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
             }
             //TODO (multidisplay): Magnification is supported only for the default display.
-            if (mService.mDisplayMagnifier != null
-                    && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) {
+            if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) {
                 MagnificationSpec spec = mService.mDisplayMagnifier
                         .getMagnificationSpecForWindowLocked(mWin);
                 if (spec != null && !spec.isNop()) {
@@ -1002,7 +1006,7 @@
                 && mWin.mBaseLayer < mAnimator.mAboveUniverseLayer);
         MagnificationSpec spec = null;
         //TODO (multidisplay): Magnification is supported only for the default display.
-        if (mService.mDisplayMagnifier != null && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) {
+        if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) {
             spec = mService.mDisplayMagnifier.getMagnificationSpecForWindowLocked(mWin);
         }
         if (applyUniverseTransformation || spec != null) {
@@ -1080,7 +1084,11 @@
 
     void updateSurfaceWindowCrop(final boolean recoveringMemory) {
         final WindowState w = mWin;
-        DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
+        final DisplayContent displayContent = w.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
+        DisplayInfo displayInfo = displayContent.getDisplayInfo();
 
         // Need to recompute a new system decor rect each time.
         if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
@@ -1181,8 +1189,7 @@
                         "SIZE " + width + "x" + height, null);
                 mSurfaceResized = true;
                 mSurfaceControl.setSize(width, height);
-                final int displayId = w.mDisplayContent.getDisplayId();
-                mAnimator.setPendingLayoutChanges(displayId,
+                mAnimator.setPendingLayoutChanges(w.getDisplayId(),
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                 if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
                     w.getStack().startDimmingIfNeeded(this);
@@ -1444,7 +1451,10 @@
                         // do a layout.  If called from within the transaction
                         // loop, this will cause it to restart with a new
                         // layout.
-                        c.mDisplayContent.layoutNeeded = true;
+                        final DisplayContent displayContent = c.getDisplayContent();
+                        if (displayContent != null) {
+                            displayContent.layoutNeeded = true;
+                        }
                     }
                 }
             }
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index bfa0942..b5e4eef 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -76,7 +76,7 @@
         return mRegistered;
     }
     /** @hide */
-    public void setRegisterd(boolean registered) {
+    public void setRegistered(boolean registered) {
         mRegistered = registered;
     }
 
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 022bf12..d34c55c 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -275,7 +275,7 @@
      * @param otaspMode is integer <code>OTASP_UNKNOWN=1<code>
      *   means the value is currently unknown and the system should wait until
      *   <code>OTASP_NEEDED=2<code> or <code>OTASP_NOT_NEEDED=3<code> is received before
-     *   making the decisision to perform OTASP or not.
+     *   making the decision to perform OTASP or not.
      *
      * @hide
      */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a785bac..3d416fb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -23,7 +23,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ITelephony;
@@ -433,7 +432,7 @@
         case RILConstants.NETWORK_MODE_GSM_UMTS:
         case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
         case RILConstants.NETWORK_MODE_LTE_WCDMA:
-        case RILConstants.NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA:
+        case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
             return PhoneConstants.PHONE_TYPE_GSM;
 
         // Use CDMA Phone for the global mode including CDMA
@@ -1258,7 +1257,7 @@
      * At registration, and when a specified telephony state
      * changes, the telephony manager invokes the appropriate
      * callback method on the listener object and passes the
-     * current (udpated) values.
+     * current (updated) values.
      * <p>
      * To unregister a listener, pass the listener object and set the
      * events argument to
@@ -1480,7 +1479,7 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
-     * @param channel is the channel id to be closed as retruned by a successful
+     * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @param cla Class of the APDU command.
      * @param instruction Instruction of the APDU command.
@@ -1502,4 +1501,102 @@
         }
         return "";
     }
+
+    /**
+     * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param itemID the ID of the item to read.
+     * @return the NV item as a String, or null on any failure.
+     * @hide
+     */
+    public String nvReadItem(int itemID) {
+        try {
+            return getITelephony().nvReadItem(itemID);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "nvReadItem RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "nvReadItem NPE", ex);
+        }
+        return "";
+    }
+
+
+    /**
+     * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param itemID the ID of the item to read.
+     * @param itemValue the value to write, as a String.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean nvWriteItem(int itemID, String itemValue) {
+        try {
+            return getITelephony().nvWriteItem(itemID, itemValue);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "nvWriteItem RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "nvWriteItem NPE", ex);
+        }
+        return false;
+    }
+
+    /**
+     * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param preferredRoamingList byte array containing the new PRL.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
+        try {
+            return getITelephony().nvWriteCdmaPrl(preferredRoamingList);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "nvWriteCdmaPrl RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "nvWriteCdmaPrl NPE", ex);
+        }
+        return false;
+    }
+
+    /**
+     * Perform the specified type of NV config reset.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset).
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean nvResetConfig(int resetType) {
+        try {
+            return getITelephony().nvResetConfig(resetType);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "nvResetConfig RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "nvResetConfig NPE", ex);
+        }
+        return false;
+    }
+
+    /**
+     * Change the radio to the specified mode.
+     * Used for device configuration by some operators.
+     *
+     * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode,
+     *                  or 3 to reset the radio.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    public boolean setRadioMode(int radioMode) {
+        try {
+            return getITelephony().setRadioMode(radioMode);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setRadioMode RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "setRadioMode NPE", ex);
+        }
+        return false;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d9e9d56..370e27a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -365,4 +365,51 @@
      */
     String iccTransmitApduLogicalChannel(int channel, int cla, int instruction,
             int p1, int p2, int p3, String data);
+
+    /**
+     * Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param itemID the ID of the item to read.
+     * @return the NV item as a String, or null on any failure.
+     */
+    String nvReadItem(int itemID);
+
+    /**
+     * Write one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param itemID the ID of the item to read.
+     * @param itemValue the value to write, as a String.
+     * @return true on success; false on any failure.
+     */
+    boolean nvWriteItem(int itemID, String itemValue);
+
+    /**
+     * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param preferredRoamingList byte array containing the new PRL.
+     * @return true on success; false on any failure.
+     */
+    boolean nvWriteCdmaPrl(in byte[] preferredRoamingList);
+
+    /**
+     * Perform the specified type of NV config reset.
+     * Used for device configuration by some CDMA operators.
+     *
+     * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset).
+     * @return true on success; false on any failure.
+     */
+    boolean nvResetConfig(int resetType);
+
+    /**
+     * Change the radio to the specified mode.
+     * Used for device configuration by some operators.
+     *
+     * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode,
+     *                  or 3 to reset the radio.
+     * @return true on success; false on any failure.
+     */
+    boolean setRadioMode(int radioMode);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 4163255..fc6c997 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -63,11 +63,11 @@
     public static final int LTE_ON_CDMA_FALSE = RILConstants.LTE_ON_CDMA_FALSE;
     public static final int LTE_ON_CDMA_TRUE = RILConstants.LTE_ON_CDMA_TRUE;
 
-    // Number presentation type for caller id display (From internal/Conneciton.java)
-    public static int PRESENTATION_ALLOWED = 1;    // normal
-    public static int PRESENTATION_RESTRICTED = 2; // block by user
-    public static int PRESENTATION_UNKNOWN = 3;    // no specified or unknown by network
-    public static int PRESENTATION_PAYPHONE = 4;   // show pay phone info
+    // Number presentation type for caller id display (From internal/Connection.java)
+    public static final int PRESENTATION_ALLOWED = 1;    // normal
+    public static final int PRESENTATION_RESTRICTED = 2; // block by user
+    public static final int PRESENTATION_UNKNOWN = 3;    // no specified or unknown by network
+    public static final int PRESENTATION_PAYPHONE = 4;   // show pay phone info
 
 
     public static final String PHONE_NAME_KEY = "phoneName";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 8e445d9..6015df0 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -72,7 +72,7 @@
                                             AVAILABLE Application Settings menu*/
     int NETWORK_MODE_LTE_CDMA_EVDO  = 8; /* LTE, CDMA and EvDo */
     int NETWORK_MODE_LTE_GSM_WCDMA  = 9; /* LTE, GSM/WCDMA */
-    int NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
+    int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
     int NETWORK_MODE_LTE_ONLY       = 11; /* LTE Only mode. */
     int NETWORK_MODE_LTE_WCDMA      = 12; /* LTE/WCDMA */
     int PREFERRED_NETWORK_MODE      = NETWORK_MODE_WCDMA_PREF;
@@ -114,6 +114,10 @@
     int DEACTIVATE_REASON_RADIO_OFF = 1;
     int DEACTIVATE_REASON_PDP_RESET = 2;
 
+    /* NV config radio reset types. */
+    int NV_CONFIG_RESET_FACTORY = 1;
+    int NV_CONFIG_RESET_NV_ONLY = 2;
+
 /*
 cat include/telephony/ril.h | \
    egrep '^#define' | \
@@ -271,6 +275,12 @@
     int RIL_REQUEST_SIM_OPEN_CHANNEL = 115;
     int RIL_REQUEST_SIM_CLOSE_CHANNEL = 116;
     int RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL = 117;
+    int RIL_REQUEST_NV_READ_ITEM = 118;
+    int RIL_REQUEST_NV_WRITE_ITEM = 119;
+    int RIL_REQUEST_NV_WRITE_CDMA_PRL = 120;
+    int RIL_REQUEST_NV_RESET_CONFIG = 121;
+    int RIL_REQUEST_SET_RADIO_MODE = 122;
+
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index a7baf1c..9ad2d42 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -125,16 +125,14 @@
      * Broadcast Action: The data connection state has changed for any one of the
      * phone's mobile data connections (eg, default, MMS or GPS specific connection).
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>phoneName</em> - A string version of the phone name.</li>
-     *   <li><em>state</em> - One of <code>"CONNECTED"</code>
-     *      <code>"CONNECTING"</code> or <code>"DISCONNNECTED"</code></li>
-     *   <li><em>apn</em> - A string that is the APN associated with this
-     *      connection.</li>
-     *   <li><em>apnType</em> - A string array of APN types associated with
-     *      this connection.  The APN type <code>"*"</code> is a special
-     *      type that means this APN services all types.</li>
-     * </ul>
+     * <dl>
+     *   <dt>phoneName</dt><dd>A string version of the phone name.</dd>
+     *   <dt>state</dt><dd>One of {@code CONNECTED}, {@code CONNECTING},
+     *      or {@code DISCONNECTED}.</dd>
+     *   <dt>apn</dt><dd>A string that is the APN associated with this connection.</dd>
+     *   <dt>apnType</dt><dd>A string array of APN types associated with this connection.
+     *      The APN type {@code *} is a special type that means this APN services all types.</dd>
+     * </dl>
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
@@ -149,16 +147,14 @@
      * Broadcast Action: Occurs when a data connection connects to a provisioning apn
      * and is broadcast by the low level data connection code.
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>apn</em> - A string that is the APN associated with this
-     *      connection.</li>
-     *   <li><em>apnType</em> - A string array of APN types associated with
-     *      this connection.  The APN type <code>"*"</code> is a special
-     *      type that means this APN services all types.</li>
-     *   <li><em>linkProperties</em> - The <code>LinkProperties</code> for this APN</li>
-     *   <li><em>linkCapabilities</em> - The <code>linkCapabilities</code> for this APN</li>
-     *   <li><em>iface</em> - A string that is the name of the interface</li>
-     * </ul>
+     * <dl>
+     *   <dt>apn</dt><dd>A string that is the APN associated with this connection.</dd>
+     *   <dt>apnType</dt><dd>A string array of APN types associated with this connection.
+     *      The APN type {@code *} is a special type that means this APN services all types.</dd>
+     *   <dt>linkProperties</dt><dd>{@code LinkProperties} for this APN.</dd>
+     *   <dt>linkCapabilities</dt><dd>The {@code LinkCapabilities} for this APN.</dd>
+     *   <dt>iface</dt><dd>A string that is the name of the interface.</dd>
+     * </dl>
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
@@ -172,12 +168,11 @@
     /**
      * Broadcast Action: An attempt to establish a data connection has failed.
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>phoneName</em> &mdash A string version of the phone name.</li>
-     *   <li><em>state</em> &mdash; One of <code>"CONNECTED"</code>
-     *      <code>"CONNECTING"</code> or <code>"DISCONNNECTED"</code></li>
-     * <li><em>reason</em> &mdash; A string indicating the reason for the failure, if available</li>
-     * </ul>
+     * <dl>
+     *   <dt>phoneName</dt><dd>A string version of the phone name.</dd>
+     *   <dt>state</dt><dd>One of {@code CONNECTED}, {@code CONNECTING}, or {code DISCONNECTED}.</dd>
+     *   <dt>reason</dt><dd>A string indicating the reason for the failure, if available.</dd>
+     * </dl>
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
@@ -192,16 +187,23 @@
     /**
      * Broadcast Action: The sim card state has changed.
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>phoneName</em> - A string version of the phone name.</li>
-     *   <li><em>ss</em> - The sim state.  One of
-     *   <code>"ABSENT"</code> <code>"LOCKED"</code>
-     *   <code>"READY"</code> <code>"ISMI"</code> <code>"LOADED"</code> </li>
-     *   <li><em>reason</em> - The reason while ss is LOCKED, otherwise is null
-     *   <code>"PIN"</code> locked on PIN1
-     *   <code>"PUK"</code> locked on PUK1
-     *   <code>"NETWORK"</code> locked on Network Personalization </li>
-     * </ul>
+     * <dl>
+     *   <dt>phoneName</dt><dd>A string version of the phone name.</dd>
+     *   <dt>ss</dt><dd>The sim state. One of:
+     *     <dl>
+     *       <dt>{@code ABSENT}</dt><dd>SIM card not found</dd>
+     *       <dt>{@code LOCKED}</dt><dd>SIM card locked (see {@code reason})</dd>
+     *       <dt>{@code READY}</dt><dd>SIM card ready</dd>
+     *       <dt>{@code IMSI}</dt><dd>FIXME: what is this state?</dd>
+     *       <dt>{@code LOADED}</dt><dd>SIM card data loaded</dd>
+     *     </dl></dd>
+     *   <dt>reason</dt><dd>The reason why ss is {@code LOCKED}; null otherwise.</dd>
+     *   <dl>
+     *       <dt>{@code PIN}</dt><dd>locked on PIN1</dd>
+     *       <dt>{@code PUK}</dt><dd>locked on PUK1</dd>
+     *       <dt>{@code NETWORK}</dt><dd>locked on network personalization</dd>
+     *   </dl>
+     * </dl>
      *
      * <p class="note">
      * Requires the READ_PHONE_STATE permission.
@@ -272,31 +274,30 @@
     /**
      * A <em>prefix</em> for the MCC/MNC filtering used with {@link #ACTION_CARRIER_SETUP}.
      * The MCC/MNC will be concatenated (zero-padded to 3 digits each) to create a final
-     * string of the form:
-     * <br />
-     * <code>android.intent.category.MCCMNC_310260</code>
+     * string of the form: {@code android.intent.category.MCCMNC_310260}
      */
     public static final String CATEGORY_MCCMNC_PREFIX = "android.intent.category.MCCMNC_";
 
     /**
      * Broadcast Action: A "secret code" has been entered in the dialer. Secret codes are
-     * of the form *#*#<code>#*#*. The intent will have the data URI:</p>
+     * of the form {@code *#*#<code>#*#*}. The intent will have the data URI:
      *
-     * <p><code>android_secret_code://&lt;code&gt;</code></p>
+     * {@code android_secret_code://<code>}
      */
-    public static final String SECRET_CODE_ACTION =
-            "android.provider.Telephony.SECRET_CODE";
+    public static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
 
     /**
      * Broadcast Action: The Service Provider string(s) have been updated.  Activities or
      * services that use these strings should update their display.
      * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>showPlmn</em> - Boolean that indicates whether the PLMN should be shown.</li>
-     *   <li><em>plmn</em> - The operator name of the registered network, as a string.</li>
-     *   <li><em>showSpn</em> - Boolean that indicates whether the SPN should be shown.</li>
-     *   <li><em>spn</em> - The service provider name, as a string.</li>
-     * </ul>
+     *
+     * <dl>
+     *   <dt>showPlmn</dt><dd>Boolean that indicates whether the PLMN should be shown.</dd>
+     *   <dt>plmn</dt><dd>The operator name of the registered network, as a string.</dd>
+     *   <dt>showSpn</dt><dd>Boolean that indicates whether the SPN should be shown.</dd>
+     *   <dt>spn</dt><dd>The service provider name, as a string.</dd>
+     * </dl>
+     *
      * Note that <em>showPlmn</em> may indicate that <em>plmn</em> should be displayed, even
      * though the value for <em>plmn</em> is null.  This can happen, for example, if the phone
      * has not registered to a network yet.  In this case the receiver may substitute an
@@ -305,8 +306,7 @@
      * It is recommended to display <em>plmn</em> before / above <em>spn</em> if
      * both are displayed.
      *
-     * <p>Note this is a protected intent that can only be sent
-     * by the system.
+     * <p>Note: this is a protected intent that can only be sent by the system.
      */
     public static final String SPN_STRINGS_UPDATED_ACTION =
             "android.provider.Telephony.SPN_STRINGS_UPDATED";
diff --git a/tests/IdleServiceTest/Android.mk b/tests/IdleServiceTest/Android.mk
new file mode 100644
index 0000000..a7879c5
--- /dev/null
+++ b/tests/IdleServiceTest/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := IdleServiceTest
+LOCAL_CERTIFICATE := platform
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
diff --git a/tests/IdleServiceTest/AndroidManifest.xml b/tests/IdleServiceTest/AndroidManifest.xml
new file mode 100644
index 0000000..16d2324
--- /dev/null
+++ b/tests/IdleServiceTest/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.idleservicetest">
+
+    <application>
+        <service android:name="TestService"
+                 android:exported="true"
+                 android:enabled="true"
+                 android:permission="android.permission.BIND_IDLE_SERVICE" >
+            <intent-filter>
+                <action android:name="android.service.idle.IdleService" />
+            </intent-filter>
+        </service>
+
+        <service android:name="CrashingTestService"
+                 android:exported="true"
+                 android:enabled="true"
+                 android:permission="android.permission.BIND_IDLE_SERVICE" >
+            <intent-filter>
+                <action android:name="android.service.idle.IdleService" />
+            </intent-filter>
+        </service>
+
+        <service android:name="TimeoutTestService"
+                 android:exported="true"
+                 android:enabled="true"
+                 android:permission="android.permission.BIND_IDLE_SERVICE" >
+            <intent-filter>
+                <action android:name="android.service.idle.IdleService" />
+            </intent-filter>
+        </service>
+
+        <!-- UnpermissionedTestService should never run because it does
+             not require the necessary permission in its <service> block -->
+        <service android:name="UnpermissionedTestService"
+                 android:exported="true"
+                 android:enabled="true" >
+            <intent-filter>
+                <action android:name="android.service.idle.IdleService" />
+            </intent-filter>
+        </service>
+
+    </application>
+</manifest>
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
new file mode 100644
index 0000000..022ebcf
--- /dev/null
+++ b/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.idleservicetest;
+
+import android.app.maintenance.IdleService;
+import android.os.Handler;
+import android.util.Log;
+
+public class CrashingTestService extends IdleService {
+    static final String TAG = "CrashingTestService";
+
+    String mNull = null;
+
+    @Override
+    public boolean onIdleStart() {
+        Log.i(TAG, "Idle maintenance: onIdleStart()");
+
+        Handler h = new Handler();
+        Runnable r = new Runnable() {
+            @Override
+            public void run() {
+                Log.i(TAG, "Explicitly crashing");
+                if (mNull.equals("")) {
+                    Log.i(TAG, "won't happen");
+                }
+            }
+        };
+        Log.i(TAG, "Posting explicit crash in 15 seconds");
+        h.postDelayed(r, 15 * 1000);
+        return true;
+    }
+
+    @Override
+    public void onIdleStop() {
+        Log.i(TAG, "Idle maintenance: onIdleStop()");
+    }
+
+}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
new file mode 100644
index 0000000..7e9805f
--- /dev/null
+++ b/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.idleservicetest;
+
+import android.app.maintenance.IdleService;
+import android.os.Handler;
+import android.util.Log;
+
+public class TestService extends IdleService {
+    static final String TAG = "TestService";
+
+    @Override
+    public boolean onIdleStart() {
+        Log.i(TAG, "Idle maintenance: onIdleStart()");
+
+        Handler h = new Handler();
+        Runnable r = new Runnable() {
+            @Override
+            public void run() {
+                Log.i(TAG, "Explicitly finishing idle");
+                finishIdle();
+            }
+        };
+        Log.i(TAG, "Posting explicit finish in 15 seconds");
+        h.postDelayed(r, 15 * 1000);
+        return true;
+    }
+
+    @Override
+    public void onIdleStop() {
+        Log.i(TAG, "Idle maintenance: onIdleStop()");
+    }
+
+}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
new file mode 100644
index 0000000..b2ba21b
--- /dev/null
+++ b/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.idleservicetest;
+
+import android.app.maintenance.IdleService;
+import android.util.Log;
+
+public class TimeoutTestService extends IdleService {
+    private static final String TAG = "TimeoutTestService";
+
+    @Override
+    public boolean onIdleStart() {
+        Log.i(TAG, "onIdleStart() but anticipating time-slice timeout");
+        return true;
+    }
+
+    @Override
+    public void onIdleStop() {
+        Log.i(TAG, "onIdleStop() so we're done");
+    }
+
+}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java
new file mode 100644
index 0000000..b9fe32b
--- /dev/null
+++ b/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.idleservicetest;
+
+import android.app.maintenance.IdleService;
+import android.util.Log;
+
+// Should never be invoked because its manifest declaration does not
+// require the necessary permission.
+public class UnpermissionedTestService extends IdleService {
+    private static final String TAG = "UnpermissionedTestService";
+
+    @Override
+    public boolean onIdleStart() {
+        Log.e(TAG, "onIdleStart() for this service should never be called!");
+        return false;
+    }
+
+    @Override
+    public void onIdleStop() {
+        Log.e(TAG, "onIdleStop() for this service should never be called!");
+    }
+
+}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index e412c27..6a3c506 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1631,9 +1631,18 @@
 // =========================================================================
 // =========================================================================
 
-status_t AaptGroup::addFile(const sp<AaptFile>& file)
+status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplicate)
 {
-    if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
+    ssize_t index = mFiles.indexOfKey(file->getGroupEntry());
+    if (index >= 0 && overwriteDuplicate) {
+        fprintf(stderr, "warning: overwriting '%s' with '%s'\n",
+                mFiles[index]->getSourceFile().string(),
+                file->getSourceFile().string());
+        removeFile(index);
+        index = -1;
+    }
+
+    if (index < 0) {
         file->mPath = mPath;
         mFiles.add(file->getGroupEntry(), file);
         return NO_ERROR;
@@ -1739,7 +1748,8 @@
     mDirs.removeItem(name);
 }
 
-status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
+status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file,
+        const bool overwrite)
 {
     sp<AaptGroup> group;
     if (mFiles.indexOfKey(leafName) >= 0) {
@@ -1749,12 +1759,12 @@
         mFiles.add(leafName, group);
     }
 
-    return group->addFile(file);
+    return group->addFile(file, overwrite);
 }
 
 ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
                             const AaptGroupEntry& kind, const String8& resType,
-                            sp<FilePathStore>& fullResPaths)
+                            sp<FilePathStore>& fullResPaths, const bool overwrite)
 {
     Vector<String8> fileNames;
     {
@@ -1813,7 +1823,7 @@
                 notAdded = true;
             }
             ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
-                                                resType, fullResPaths);
+                                                resType, fullResPaths, overwrite);
             if (res < NO_ERROR) {
                 return res;
             }
@@ -1823,7 +1833,7 @@
             count += res;
         } else if (type == kFileTypeRegular) {
             sp<AaptFile> file = new AaptFile(pathName, kind, resType);
-            status_t err = addLeafFile(fileNames[i], file);
+            status_t err = addLeafFile(fileNames[i], file, overwrite);
             if (err != NO_ERROR) {
                 return err;
             }
@@ -2089,24 +2099,24 @@
     /*
      * If a directory of custom assets was supplied, slurp 'em up.
      */
-    if (bundle->getAssetSourceDir()) {
-        const char* assetDir = bundle->getAssetSourceDir();
-
-        FileType type = getFileType(assetDir);
+    const Vector<const char*>& assetDirs = bundle->getAssetSourceDirs();
+    const int AN = assetDirs.size();
+    for (int i = 0; i < AN; i++) {
+        FileType type = getFileType(assetDirs[i]);
         if (type == kFileTypeNonexistent) {
-            fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
+            fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDirs[i]);
             return UNKNOWN_ERROR;
         }
         if (type != kFileTypeDirectory) {
-            fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
+            fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDirs[i]);
             return UNKNOWN_ERROR;
         }
 
-        String8 assetRoot(assetDir);
+        String8 assetRoot(assetDirs[i]);
         sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
         AaptGroupEntry group;
         count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
-                                            String8(), mFullAssetPaths);
+                                            String8(), mFullAssetPaths, true);
         if (count < 0) {
             totalCount = count;
             goto bail;
@@ -2116,9 +2126,10 @@
         }
         totalCount += count;
 
-        if (bundle->getVerbose())
+        if (bundle->getVerbose()) {
             printf("Found %d custom asset file%s in %s\n",
-                   count, (count==1) ? "" : "s", assetDir);
+                   count, (count==1) ? "" : "s", assetDirs[i]);
+        }
     }
 
     /*
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 5cfa913..9cc9007 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -235,7 +235,7 @@
     const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& getFiles() const
         { return mFiles; }
 
-    status_t addFile(const sp<AaptFile>& file);
+    status_t addFile(const sp<AaptFile>& file, const bool overwriteDuplicate=false);
     void removeFile(size_t index);
 
     void print(const String8& prefix) const;
@@ -301,12 +301,14 @@
     status_t addDir(const String8& name, const sp<AaptDir>& dir);
     sp<AaptDir> makeDir(const String8& name);
     status_t addLeafFile(const String8& leafName,
-                         const sp<AaptFile>& file);
+                         const sp<AaptFile>& file,
+                         const bool overwrite=false);
     virtual ssize_t slurpFullTree(Bundle* bundle,
                                   const String8& srcDir,
                                   const AaptGroupEntry& kind,
                                   const String8& resType,
-                                  sp<FilePathStore>& fullResPaths);
+                                  sp<FilePathStore>& fullResPaths,
+                                  const bool overwrite=false);
 
     String8 mLeaf;
     String8 mPath;
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 52d9266..cbeaae8 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -55,7 +55,6 @@
           mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL),
           mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
           mAutoAddOverlay(false), mGenDependencies(false),
-          mAssetSourceDir(NULL),
           mCrunchedOutputDir(NULL), mProguardFile(NULL),
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
           mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
@@ -128,8 +127,8 @@
     /*
      * Input options.
      */
-    const char* getAssetSourceDir() const { return mAssetSourceDir; }
-    void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; }
+    const android::Vector<const char*>& getAssetSourceDirs() const { return mAssetSourceDirs; }
+    void addAssetSourceDir(const char* dir) { mAssetSourceDirs.insertAt(dir,0); }
     const char* getCrunchedOutputDir() const { return mCrunchedOutputDir; }
     void setCrunchedOutputDir(const char* dir) { mCrunchedOutputDir = dir; }
     const char* getProguardFile() const { return mProguardFile; }
@@ -266,7 +265,6 @@
     const char* mInstrumentationPackageNameOverride;
     bool        mAutoAddOverlay;
     bool        mGenDependencies;
-    const char* mAssetSourceDir;
     const char* mCrunchedOutputDir;
     const char* mProguardFile;
     const char* mAndroidManifestFile;
@@ -278,6 +276,7 @@
     android::Vector<const char*> mPackageIncludes;
     android::Vector<const char*> mJarFiles;
     android::Vector<const char*> mNoCompressExtensions;
+    android::Vector<const char*> mAssetSourceDirs;
     android::Vector<const char*> mResourceSourceDirs;
 
     const char* mManifestMinSdkVersion;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index c527388..48e3125 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -2034,7 +2034,7 @@
 
     N = bundle->getFileSpecCount();
     if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
-            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) {
+            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
         fprintf(stderr, "ERROR: no input files\n");
         goto bail;
     }
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 51a1248..1ed4630 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -349,7 +349,7 @@
                     goto bail;
                 }
                 convertPath(argv[0]);
-                bundle.setAssetSourceDir(argv[0]);
+                bundle.addAssetSourceDir(argv[0]);
                 break;
             case 'G':
                 argc--;
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 8794452..c3e06d2 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -51,6 +51,7 @@
     private BridgeContext mContext;
     private IProjectCallback mProjectCallback;
     private boolean[] mPlatformResourceFlag = new boolean[1];
+    private TypedValue mTmpValue = new TypedValue();
 
     /**
      * Simpler wrapper around FileInputStream. This is used when the input stream represent