Merge "camera2: Fix frame ID returned by legacy mode shim."
diff --git a/Android.mk b/Android.mk
index 56e9df6..936b41a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -152,6 +152,7 @@
 	core/java/android/hardware/hdmi/IHdmiControlService.aidl \
 	core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \
 	core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl \
+	core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl \
 	core/java/android/hardware/input/IInputManager.aidl \
 	core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
 	core/java/android/hardware/location/IFusedLocationHardware.aidl \
@@ -175,6 +176,7 @@
 	core/java/android/nfc/INfcAdapterExtras.aidl \
 	core/java/android/nfc/INfcTag.aidl \
 	core/java/android/nfc/INfcCardEmulation.aidl \
+	core/java/android/nfc/INfcLockscreenDispatch.aidl \
 	core/java/android/os/IBatteryPropertiesListener.aidl \
 	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
 	core/java/android/os/ICancellationSignal.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1968a78..b6a47f2 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -202,6 +202,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes/android/app/maintenance)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes/android/app/maintenance)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
 
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index 3b311e3..6a8b2be 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -510,7 +510,7 @@
     field public static final int excludeClass = 16843844; // 0x1010444
     field public static final int excludeFromRecents = 16842775; // 0x1010017
     field public static final int excludeId = 16843843; // 0x1010443
-    field public static final int excludeViewName = 16843856; // 0x1010450
+    field public static final int excludeName = 16843856; // 0x1010450
     field public static final int exitFadeDuration = 16843533; // 0x101030d
     field public static final int expandableListPreferredChildIndicatorLeft = 16842834; // 0x1010052
     field public static final int expandableListPreferredChildIndicatorRight = 16842835; // 0x1010053
@@ -957,6 +957,7 @@
     field public static final int ratingBarStyleIndicator = 16843280; // 0x1010210
     field public static final int ratingBarStyleSmall = 16842877; // 0x101007d
     field public static final int readPermission = 16842759; // 0x1010007
+    field public static final int relinquishTaskIdentity = 16843896; // 0x1010478
     field public static final int repeatCount = 16843199; // 0x10101bf
     field public static final int repeatMode = 16843200; // 0x10101c0
     field public static final int reqFiveWayNav = 16843314; // 0x1010232
@@ -1153,9 +1154,9 @@
     field public static final int targetClass = 16842799; // 0x101002f
     field public static final int targetDescriptions = 16843680; // 0x10103a0
     field public static final int targetId = 16843740; // 0x10103dc
+    field public static final int targetName = 16843855; // 0x101044f
     field public static final int targetPackage = 16842785; // 0x1010021
     field public static final int targetSdkVersion = 16843376; // 0x1010270
-    field public static final int targetViewName = 16843855; // 0x101044f
     field public static final int taskAffinity = 16842770; // 0x1010012
     field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
     field public static final int taskCloseExitAnimation = 16842943; // 0x10100bf
@@ -1238,6 +1239,8 @@
     field public static final int thumbTintMode = 16843892; // 0x1010474
     field public static final int thumbnail = 16843429; // 0x10102a5
     field public static final int tileMode = 16843265; // 0x1010201
+    field public static final int tileModeX = 16843897; // 0x1010479
+    field public static final int tileModeY = 16843898; // 0x101047a
     field public static final int timeZone = 16843724; // 0x10103cc
     field public static final int tint = 16843041; // 0x1010121
     field public static final int tintMode = 16843797; // 0x1010415
@@ -1265,6 +1268,7 @@
     field public static final int transformPivotY = 16843553; // 0x1010321
     field public static final int transition = 16843743; // 0x10103df
     field public static final int transitionGroup = 16843803; // 0x101041b
+    field public static final int transitionName = 16843802; // 0x101041a
     field public static final int transitionOrdering = 16843744; // 0x10103e0
     field public static final int translateX = 16843868; // 0x101045c
     field public static final int translateY = 16843869; // 0x101045d
@@ -1299,7 +1303,6 @@
     field public static final int verticalGap = 16843328; // 0x1010240
     field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
     field public static final int verticalSpacing = 16843029; // 0x1010115
-    field public static final int viewName = 16843802; // 0x101041a
     field public static final int viewportHeight = 16843805; // 0x101041d
     field public static final int viewportWidth = 16843804; // 0x101041c
     field public static final int visibility = 16842972; // 0x10100dc
@@ -2524,7 +2527,14 @@
 
   public static final class R.transition {
     ctor public R.transition();
+    field public static final int explode = 17760259; // 0x10f0003
+    field public static final int fade = 17760258; // 0x10f0002
+    field public static final int move = 17760257; // 0x10f0001
     field public static final int no_transition = 17760256; // 0x10f0000
+    field public static final int slide_bottom = 17760260; // 0x10f0004
+    field public static final int slide_left = 17760263; // 0x10f0007
+    field public static final int slide_right = 17760262; // 0x10f0006
+    field public static final int slide_top = 17760261; // 0x10f0005
   }
 
   public static final class R.xml {
@@ -8085,6 +8095,7 @@
     field public static final int FLAG_IMMERSIVE = 2048; // 0x800
     field public static final int FLAG_MULTIPROCESS = 1; // 0x1
     field public static final int FLAG_NO_HISTORY = 128; // 0x80
+    field public static final int FLAG_RELINQUISH_TASK_IDENTITY = 4096; // 0x1000
     field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
     field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
     field public static final int LAUNCH_MULTIPLE = 0; // 0x0
@@ -11244,6 +11255,17 @@
     method public void addTransition(int, int, android.graphics.drawable.AnimationDrawable, boolean);
   }
 
+  public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable {
+    ctor public AnimatedVectorDrawable();
+    method public void draw(android.graphics.Canvas);
+    method public int getOpacity();
+    method public boolean isRunning();
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void start();
+    method public void stop();
+  }
+
   public class AnimationDrawable extends android.graphics.drawable.DrawableContainer implements android.graphics.drawable.Animatable java.lang.Runnable {
     ctor public AnimationDrawable();
     method public void addFrame(android.graphics.drawable.Drawable, int);
@@ -11643,8 +11665,6 @@
     method public int getOpacity();
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setPadding(android.graphics.Rect);
-    method public void setPadding(int, int, int, int);
   }
 
 }
@@ -13796,6 +13816,7 @@
     method public deprecated void setWiredHeadsetOn(boolean);
     method public deprecated boolean shouldVibrate(int);
     method public void startBluetoothSco();
+    method public void startBluetoothScoVirtualCall();
     method public void stopBluetoothSco();
     method public void unloadSoundEffects();
     method public void unregisterMediaButtonEventReceiver(android.content.ComponentName);
@@ -14480,6 +14501,11 @@
     method public java.lang.String getDefaultUrl();
   }
 
+  public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
+    ctor public MediaDrm.MediaDrmStateException(int, java.lang.String);
+    method public int getErrorCode();
+  }
+
   public static abstract interface MediaDrm.OnEventListener {
     method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
   }
@@ -15348,6 +15374,19 @@
     ctor public UnsupportedSchemeException(java.lang.String);
   }
 
+  public abstract class VolumeProvider {
+    ctor public VolumeProvider(int, int);
+    method public final int getMaxVolume();
+    method public final int getVolumeControl();
+    method public final void notifyVolumeChanged();
+    method public void onAdjustVolumeBy(int);
+    method public abstract int onGetCurrentVolume();
+    method public void onSetVolumeTo(int);
+    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+  }
+
 }
 
 package android.media.audiofx {
@@ -15714,6 +15753,7 @@
     method public android.media.session.PlaybackState getPlaybackState();
     method public int getRatingType();
     method public android.media.session.MediaController.TransportControls getTransportControls();
+    method public android.media.session.MediaController.VolumeInfo getVolumeInfo();
     method public void removeCallback(android.media.session.MediaController.Callback);
     method public void sendControlCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
   }
@@ -15737,6 +15777,14 @@
     method public void stop();
   }
 
+  public static final class MediaController.VolumeInfo {
+    method public int getAudioStream();
+    method public int getCurrentVolume();
+    method public int getMaxVolume();
+    method public int getVolumeControl();
+    method public int getVolumeType();
+  }
+
   public final class MediaSession {
     method public void addCallback(android.media.session.MediaSession.Callback);
     method public void addCallback(android.media.session.MediaSession.Callback, android.os.Handler);
@@ -15754,9 +15802,11 @@
     method public void setMetadata(android.media.MediaMetadata);
     method public void setPlaybackState(android.media.session.PlaybackState);
     method public void setPlaybackToLocal(int);
-    method public void setPlaybackToRemote(android.media.session.RemoteVolumeProvider);
+    method public void setPlaybackToRemote(android.media.VolumeProvider);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+    field public static final int VOLUME_TYPE_LOCAL = 1; // 0x1
+    field public static final int VOLUME_TYPE_REMOTE = 2; // 0x2
   }
 
   public static abstract class MediaSession.Callback {
@@ -15827,19 +15877,6 @@
     field public static final int STATE_STOPPED = 1; // 0x1
   }
 
-  public abstract class RemoteVolumeProvider {
-    ctor public RemoteVolumeProvider(int, int);
-    method public final int getMaxVolume();
-    method public final int getVolumeControl();
-    method public final void notifyVolumeChanged();
-    method public void onAdjustVolumeBy(int);
-    method public abstract int onGetCurrentVolume();
-    method public void onSetVolumeTo(int);
-    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
-    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
-    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
-  }
-
 }
 
 package android.media.tv {
@@ -17638,6 +17675,7 @@
     method public boolean invokeBeam(android.app.Activity);
     method public boolean isEnabled();
     method public boolean isNdefPushEnabled();
+    method public boolean registerLockscreenDispatch(android.nfc.NfcAdapter.NfcLockscreenDispatch, java.lang.String[]);
     method public void setBeamPushUris(android.net.Uri[], android.app.Activity);
     method public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
     method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
@@ -17673,6 +17711,10 @@
     method public abstract android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
   }
 
+  public static abstract interface NfcAdapter.NfcLockscreenDispatch {
+    method public abstract boolean onTagDetected(android.nfc.Tag);
+  }
+
   public static abstract interface NfcAdapter.OnNdefPushCompleteCallback {
     method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
   }
@@ -27795,7 +27837,6 @@
     field public static final java.lang.String ACTION_CALL_SERVICE;
     field public static final java.lang.String ACTION_CALL_SERVICE_PROVIDER;
     field public static final java.lang.String ACTION_CALL_SERVICE_SELECTOR;
-    field public static final java.lang.String ACTION_CHANGE_DEFAULT_PHONE = "android.telecomm.ACTION_CHANGE_DEFAULT_PHONE";
     field public static final java.lang.String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
@@ -27803,7 +27844,6 @@
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
     field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
     field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS";
-    field public static final java.lang.String EXTRA_PACKAGE_NAME = "package";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
   }
 
@@ -30506,8 +30546,8 @@
     method public android.transition.TransitionPropagation getPropagation();
     method public long getStartDelay();
     method public java.util.List<java.lang.Integer> getTargetIds();
+    method public java.util.List<java.lang.String> getTargetNames();
     method public java.util.List<java.lang.Class> getTargetTypes();
-    method public java.util.List<java.lang.String> getTargetViewNames();
     method public java.util.List<android.view.View> getTargets();
     method public java.lang.String[] getTransitionProperties();
     method public android.transition.TransitionValues getTransitionValues(android.view.View, boolean);
@@ -30525,7 +30565,7 @@
     field public static final int MATCH_ID = 3; // 0x3
     field public static final int MATCH_INSTANCE = 1; // 0x1
     field public static final int MATCH_ITEM_ID = 4; // 0x4
-    field public static final int MATCH_VIEW_NAME = 2; // 0x2
+    field public static final int MATCH_NAME = 2; // 0x2
   }
 
   public static abstract class Transition.EpicenterCallback {
@@ -32716,13 +32756,13 @@
     method protected int getTopPaddingOffset();
     method public android.view.TouchDelegate getTouchDelegate();
     method public java.util.ArrayList<android.view.View> getTouchables();
+    method public java.lang.String getTransitionName();
     method public float getTranslationX();
     method public float getTranslationY();
     method public float getTranslationZ();
     method public int getVerticalFadingEdgeLength();
     method public int getVerticalScrollbarPosition();
     method public int getVerticalScrollbarWidth();
-    method public java.lang.String getViewName();
     method public android.view.ViewTreeObserver getViewTreeObserver();
     method public int getVisibility();
     method public final int getWidth();
@@ -32979,13 +33019,13 @@
     method public void setTextDirection(int);
     method public final void setTop(int);
     method public void setTouchDelegate(android.view.TouchDelegate);
+    method public final void setTransitionName(java.lang.String);
     method public void setTranslationX(float);
     method public void setTranslationY(float);
     method public void setTranslationZ(float);
     method public void setVerticalFadingEdgeEnabled(boolean);
     method public void setVerticalScrollBarEnabled(boolean);
     method public void setVerticalScrollbarPosition(int);
-    method public final void setViewName(java.lang.String);
     method public void setVisibility(int);
     method public void setWillNotCacheDrawing(boolean);
     method public void setWillNotDraw(boolean);
@@ -35254,6 +35294,7 @@
     method public abstract long getResources();
     method public abstract void grant(long);
     field public static final long RESOURCE_AUDIO_CAPTURE = 4L; // 0x4L
+    field public static final long RESOURCE_PROTECTED_MEDIA_ID = 8L; // 0x8L
     field public static final long RESOURCE_VIDEO_CAPTURE = 2L; // 0x2L
   }
 
@@ -48249,6 +48290,35 @@
     method public V replace(K, V);
   }
 
+  public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
+    ctor public ConcurrentLinkedDeque();
+    ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
+    method public void addFirst(E);
+    method public void addLast(E);
+    method public java.util.Iterator<E> descendingIterator();
+    method public E element();
+    method public E getFirst();
+    method public E getLast();
+    method public java.util.Iterator<E> iterator();
+    method public boolean offer(E);
+    method public boolean offerFirst(E);
+    method public boolean offerLast(E);
+    method public E peek();
+    method public E peekFirst();
+    method public E peekLast();
+    method public E poll();
+    method public E pollFirst();
+    method public E pollLast();
+    method public E pop();
+    method public void push(E);
+    method public E remove();
+    method public E removeFirst();
+    method public boolean removeFirstOccurrence(java.lang.Object);
+    method public E removeLast();
+    method public boolean removeLastOccurrence(java.lang.Object);
+    method public int size();
+  }
+
   public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
     ctor public ConcurrentLinkedQueue();
     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
@@ -48489,6 +48559,94 @@
     method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
   }
 
+  public class ForkJoinPool extends java.util.concurrent.AbstractExecutorService {
+    ctor public ForkJoinPool();
+    ctor public ForkJoinPool(int);
+    ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean);
+    method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit);
+    method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method protected int drainTasksTo(java.util.Collection<? super java.util.concurrent.ForkJoinTask<?>>);
+    method public void execute(java.util.concurrent.ForkJoinTask<?>);
+    method public void execute(java.lang.Runnable);
+    method public int getActiveThreadCount();
+    method public boolean getAsyncMode();
+    method public java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory getFactory();
+    method public int getParallelism();
+    method public int getPoolSize();
+    method public int getQueuedSubmissionCount();
+    method public long getQueuedTaskCount();
+    method public int getRunningThreadCount();
+    method public long getStealCount();
+    method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
+    method public boolean hasQueuedSubmissions();
+    method public T invoke(java.util.concurrent.ForkJoinTask<T>);
+    method public boolean isQuiescent();
+    method public boolean isShutdown();
+    method public boolean isTerminated();
+    method public boolean isTerminating();
+    method public static void managedBlock(java.util.concurrent.ForkJoinPool.ManagedBlocker) throws java.lang.InterruptedException;
+    method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
+    method public void shutdown();
+    method public java.util.List<java.lang.Runnable> shutdownNow();
+    method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
+    field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
+  }
+
+  public static abstract interface ForkJoinPool.ForkJoinWorkerThreadFactory {
+    method public abstract java.util.concurrent.ForkJoinWorkerThread newThread(java.util.concurrent.ForkJoinPool);
+  }
+
+  public static abstract interface ForkJoinPool.ManagedBlocker {
+    method public abstract boolean block() throws java.lang.InterruptedException;
+    method public abstract boolean isReleasable();
+  }
+
+  public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
+    ctor public ForkJoinTask();
+    method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
+    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
+    method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
+    method public boolean cancel(boolean);
+    method public void complete(V);
+    method public void completeExceptionally(java.lang.Throwable);
+    method protected abstract boolean exec();
+    method public final java.util.concurrent.ForkJoinTask<V> fork();
+    method public final V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public final V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public final java.lang.Throwable getException();
+    method public static java.util.concurrent.ForkJoinPool getPool();
+    method public static int getQueuedTaskCount();
+    method public abstract V getRawResult();
+    method public static int getSurplusQueuedTaskCount();
+    method public static void helpQuiesce();
+    method public static boolean inForkJoinPool();
+    method public final V invoke();
+    method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
+    method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
+    method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
+    method public final boolean isCancelled();
+    method public final boolean isCompletedAbnormally();
+    method public final boolean isCompletedNormally();
+    method public final boolean isDone();
+    method public final V join();
+    method protected static java.util.concurrent.ForkJoinTask<?> peekNextLocalTask();
+    method protected static java.util.concurrent.ForkJoinTask<?> pollNextLocalTask();
+    method protected static java.util.concurrent.ForkJoinTask<?> pollTask();
+    method public final void quietlyInvoke();
+    method public final void quietlyJoin();
+    method public void reinitialize();
+    method protected abstract void setRawResult(V);
+    method public boolean tryUnfork();
+  }
+
+  public class ForkJoinWorkerThread extends java.lang.Thread {
+    ctor protected ForkJoinWorkerThread(java.util.concurrent.ForkJoinPool);
+    method public java.util.concurrent.ForkJoinPool getPool();
+    method public int getPoolIndex();
+    method protected void onStart();
+    method protected void onTermination(java.lang.Throwable);
+  }
+
   public abstract interface Future {
     method public abstract boolean cancel(boolean);
     method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
@@ -48573,6 +48731,52 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
+  public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
+    ctor public LinkedTransferQueue();
+    ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
+    method public int drainTo(java.util.Collection<? super E>);
+    method public int drainTo(java.util.Collection<? super E>, int);
+    method public int getWaitingConsumerCount();
+    method public boolean hasWaitingConsumer();
+    method public java.util.Iterator<E> iterator();
+    method public boolean offer(E, long, java.util.concurrent.TimeUnit);
+    method public boolean offer(E);
+    method public E peek();
+    method public E poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public E poll();
+    method public void put(E);
+    method public int remainingCapacity();
+    method public int size();
+    method public E take() throws java.lang.InterruptedException;
+    method public void transfer(E) throws java.lang.InterruptedException;
+    method public boolean tryTransfer(E);
+    method public boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+  }
+
+  public class Phaser {
+    ctor public Phaser();
+    ctor public Phaser(int);
+    ctor public Phaser(java.util.concurrent.Phaser);
+    ctor public Phaser(java.util.concurrent.Phaser, int);
+    method public int arrive();
+    method public int arriveAndAwaitAdvance();
+    method public int arriveAndDeregister();
+    method public int awaitAdvance(int);
+    method public int awaitAdvanceInterruptibly(int) throws java.lang.InterruptedException;
+    method public int awaitAdvanceInterruptibly(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public int bulkRegister(int);
+    method public void forceTermination();
+    method public int getArrivedParties();
+    method public java.util.concurrent.Phaser getParent();
+    method public final int getPhase();
+    method public int getRegisteredParties();
+    method public java.util.concurrent.Phaser getRoot();
+    method public int getUnarrivedParties();
+    method public boolean isTerminated();
+    method protected boolean onAdvance(int, int);
+    method public int register();
+  }
+
   public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
     ctor public PriorityBlockingQueue();
     ctor public PriorityBlockingQueue(int);
@@ -48593,6 +48797,22 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
+  public abstract class RecursiveAction extends java.util.concurrent.ForkJoinTask {
+    ctor public RecursiveAction();
+    method protected abstract void compute();
+    method protected final boolean exec();
+    method public final java.lang.Void getRawResult();
+    method protected final void setRawResult(java.lang.Void);
+  }
+
+  public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
+    ctor public RecursiveTask();
+    method protected abstract V compute();
+    method protected final boolean exec();
+    method public final V getRawResult();
+    method protected final void setRawResult(V);
+  }
+
   public class RejectedExecutionException extends java.lang.RuntimeException {
     ctor public RejectedExecutionException();
     ctor public RejectedExecutionException(java.lang.String);
@@ -48631,12 +48851,14 @@
     method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
+    method public boolean getRemoveOnCancelPolicy();
     method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
     method public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean);
+    method public void setRemoveOnCancelPolicy(boolean);
   }
 
   public class Semaphore implements java.io.Serializable {
@@ -48682,6 +48904,15 @@
     method public abstract java.lang.Thread newThread(java.lang.Runnable);
   }
 
+  public class ThreadLocalRandom extends java.util.Random {
+    method public static java.util.concurrent.ThreadLocalRandom current();
+    method public double nextDouble(double);
+    method public double nextDouble(double, double);
+    method public int nextInt(int, int);
+    method public long nextLong(long);
+    method public long nextLong(long, long);
+  }
+
   public class ThreadPoolExecutor extends java.util.concurrent.AbstractExecutorService {
     ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>);
     ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>, java.util.concurrent.ThreadFactory);
@@ -48769,6 +49000,14 @@
     ctor public TimeoutException(java.lang.String);
   }
 
+  public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
+    method public abstract int getWaitingConsumerCount();
+    method public abstract boolean hasWaitingConsumer();
+    method public abstract void transfer(E) throws java.lang.InterruptedException;
+    method public abstract boolean tryTransfer(E);
+    method public abstract boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+  }
+
 }
 
 package java.util.concurrent.atomic {
@@ -48978,6 +49217,7 @@
     method public final int getWaitQueueLength(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
     method public final java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
     method public final boolean hasContended();
+    method public final boolean hasQueuedPredecessors();
     method public final boolean hasQueuedThreads();
     method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
     method protected boolean isHeldExclusively();
@@ -49024,6 +49264,7 @@
     method public final int getWaitQueueLength(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
     method public final java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
     method public final boolean hasContended();
+    method public final boolean hasQueuedPredecessors();
     method public final boolean hasQueuedThreads();
     method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
     method protected boolean isHeldExclusively();
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 6296dd1..6b2a0e2 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -52,13 +52,13 @@
     );
 }
 
-static SkBitmap::Config flinger2skia(PixelFormat f)
+static SkColorType flinger2skia(PixelFormat f)
 {
     switch (f) {
         case PIXEL_FORMAT_RGB_565:
-            return SkBitmap::kRGB_565_Config;
+            return kRGB_565_SkColorType;
         default:
-            return SkBitmap::kARGB_8888_Config;
+            return kN32_SkColorType;
     }
 }
 
@@ -174,9 +174,10 @@
 
     if (base) {
         if (png) {
+            const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f),
+                                                       kPremul_SkAlphaType);
             SkBitmap b;
-            b.setConfig(flinger2skia(f), w, h, s*bytesPerPixel(f));
-            b.setPixels((void*)base);
+            b.installPixels(info, const_cast<void*>(base), s*bytesPerPixel(f));
             SkDynamicMemoryWStream stream;
             SkImageEncoder::EncodeStream(&stream, b,
                     SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 39fcf73..0f5e954 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -23,10 +23,12 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.Path;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.PathParser;
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
+import android.view.InflateException;
 import android.view.animation.AnimationUtils;
 
 import com.android.internal.R;
@@ -47,7 +49,7 @@
  * <em>something</em> file.)
  */
 public class AnimatorInflater {
-
+    private static final String TAG = "AnimatorInflater";
     /**
      * These flags are used when parsing AnimatorSet objects
      */
@@ -59,9 +61,12 @@
      */
     private static final int VALUE_TYPE_FLOAT       = 0;
     private static final int VALUE_TYPE_INT         = 1;
+    private static final int VALUE_TYPE_PATH        = 2;
     private static final int VALUE_TYPE_COLOR       = 4;
     private static final int VALUE_TYPE_CUSTOM      = 5;
 
+    private static final boolean DBG_ANIMATOR_INFLATER = false;
+
     /**
      * Loads an {@link Animator} object from a resource
      *
@@ -189,6 +194,56 @@
     }
 
     /**
+     * PathDataEvaluator is used to interpolate between two paths which are
+     * represented in the same format but different control points' values.
+     * The path is represented as an array of PathDataNode here, which is
+     * fundamentally an array of floating point numbers.
+     */
+    private static class PathDataEvaluator implements TypeEvaluator<PathParser.PathDataNode[]> {
+        private PathParser.PathDataNode[] mNodeArray;
+
+        /**
+         * Create a PathParser.PathDataNode[] that does not reuse the animated value.
+         * Care must be taken when using this option because on every evaluation
+         * a new <code>PathParser.PathDataNode[]</code> will be allocated.
+         */
+        private PathDataEvaluator() {}
+
+        /**
+         * Create a PathDataEvaluator that reuses <code>nodeArray</code> for every evaluate() call.
+         * Caution must be taken to ensure that the value returned from
+         * {@link android.animation.ValueAnimator#getAnimatedValue()} is not cached, modified, or
+         * used across threads. The value will be modified on each <code>evaluate()</code> call.
+         *
+         * @param nodeArray The array to modify and return from <code>evaluate</code>.
+         */
+        public PathDataEvaluator(PathParser.PathDataNode[] nodeArray) {
+            mNodeArray = nodeArray;
+        }
+
+        @Override
+        public PathParser.PathDataNode[] evaluate(float fraction,
+                PathParser.PathDataNode[] startPathData,
+                PathParser.PathDataNode[] endPathData) {
+            if (!PathParser.canMorph(startPathData, endPathData)) {
+                throw new IllegalArgumentException("Can't interpolate between"
+                        + " two incompatible pathData");
+            }
+
+            if (mNodeArray == null || !PathParser.canMorph(mNodeArray, startPathData)) {
+                mNodeArray = PathParser.deepCopyNodes(startPathData);
+            }
+
+            for (int i = 0; i < startPathData.length; i++) {
+                mNodeArray[i].interpolatePathDataNode(startPathData[i],
+                        endPathData[i], fraction);
+            }
+
+            return mNodeArray;
+        }
+    }
+
+    /**
      * @param anim Null if this is a ValueAnimator, otherwise this is an
      *            ObjectAnimator
      * @param arrayAnimator Incoming typed array for Animator's attributes.
@@ -209,27 +264,157 @@
         }
 
         TypeEvaluator evaluator = null;
-        int valueFromIndex = R.styleable.Animator_valueFrom;
-        int valueToIndex = R.styleable.Animator_valueTo;
 
         boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
 
-        TypedValue tvFrom = arrayAnimator.peekValue(valueFromIndex);
+        TypedValue tvFrom = arrayAnimator.peekValue(R.styleable.Animator_valueFrom);
         boolean hasFrom = (tvFrom != null);
         int fromType = hasFrom ? tvFrom.type : 0;
-        TypedValue tvTo = arrayAnimator.peekValue(valueToIndex);
+        TypedValue tvTo = arrayAnimator.peekValue(R.styleable.Animator_valueTo);
         boolean hasTo = (tvTo != null);
         int toType = hasTo ? tvTo.type : 0;
 
-        if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
-                (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                        (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
-            // special case for colors: ignore valueType and get ints
-            getFloats = false;
-            evaluator = ArgbEvaluator.getInstance();
+        // TODO: Further clean up this part of code into 4 types : path, color,
+        // integer and float.
+        if (valueType == VALUE_TYPE_PATH) {
+            evaluator = setupAnimatorForPath(anim, arrayAnimator);
+        } else {
+            // Integer and float value types are handled here.
+            if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+                    (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
+                    (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+                            (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
+                // special case for colors: ignore valueType and get ints
+                getFloats = false;
+                evaluator = ArgbEvaluator.getInstance();
+            }
+            setupValues(anim, arrayAnimator, getFloats, hasFrom, fromType, hasTo, toType);
         }
 
+        anim.setDuration(duration);
+        anim.setStartDelay(startDelay);
+
+        if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) {
+            anim.setRepeatCount(
+                    arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0));
+        }
+        if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) {
+            anim.setRepeatMode(
+                    arrayAnimator.getInt(R.styleable.Animator_repeatMode,
+                            ValueAnimator.RESTART));
+        }
+        if (evaluator != null) {
+            anim.setEvaluator(evaluator);
+        }
+
+        if (arrayObjectAnimator != null) {
+            setupObjectAnimator(anim, arrayObjectAnimator, getFloats);
+        }
+    }
+
+    /**
+     * Setup the Animator to achieve path morphing.
+     *
+     * @param anim The target Animator which will be updated.
+     * @param arrayAnimator TypedArray for the ValueAnimator.
+     * @return the PathDataEvaluator.
+     */
+    private static TypeEvaluator setupAnimatorForPath(ValueAnimator anim,
+             TypedArray arrayAnimator) {
+        TypeEvaluator evaluator = null;
+        String fromString = arrayAnimator.getString(R.styleable.Animator_valueFrom);
+        String toString = arrayAnimator.getString(R.styleable.Animator_valueTo);
+        PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
+        PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);
+
+        if (nodesFrom != null) {
+            if (nodesTo != null) {
+                anim.setObjectValues(nodesFrom, nodesTo);
+                if (!PathParser.canMorph(nodesFrom, nodesTo)) {
+                    throw new InflateException(arrayAnimator.getPositionDescription()
+                            + " Can't morph from " + fromString + " to " + toString);
+                }
+            } else {
+                anim.setObjectValues((Object)nodesFrom);
+            }
+            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
+        } else if (nodesTo != null) {
+            anim.setObjectValues((Object)nodesTo);
+            evaluator = new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
+        }
+
+        if (DBG_ANIMATOR_INFLATER && evaluator != null) {
+            Log.v(TAG, "create a new PathDataEvaluator here");
+        }
+
+        return evaluator;
+    }
+
+    /**
+     * Setup ObjectAnimator's property or values from pathData.
+     *
+     * @param anim The target Animator which will be updated.
+     * @param arrayObjectAnimator TypedArray for the ObjectAnimator.
+     * @param getFloats True if the value type is float.
+     */
+    private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator,
+            boolean getFloats) {
+        ObjectAnimator oa = (ObjectAnimator) anim;
+        String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData);
+
+        // Note that if there is a pathData defined in the Object Animator,
+        // valueFrom / valueTo will be ignored.
+        if (pathData != null) {
+            String propertyXName =
+                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName);
+            String propertyYName =
+                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName);
+
+            if (propertyXName == null && propertyYName == null) {
+                throw new InflateException(arrayObjectAnimator.getPositionDescription()
+                        + " propertyXName or propertyYName is needed for PathData");
+            } else {
+                Path path = PathParser.createPathFromPathData(pathData);
+                Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, !getFloats);
+                PropertyValuesHolder x = null;
+                PropertyValuesHolder y = null;
+                if (propertyXName != null) {
+                    x = PropertyValuesHolder.ofKeyframe(propertyXName, keyframes[0]);
+                }
+                if (propertyYName != null) {
+                    y = PropertyValuesHolder.ofKeyframe(propertyYName, keyframes[1]);
+                }
+                if (x == null) {
+                    oa.setValues(y);
+                } else if (y == null) {
+                    oa.setValues(x);
+                } else {
+                    oa.setValues(x, y);
+                }
+            }
+        } else {
+            String propertyName =
+                    arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName);
+            oa.setPropertyName(propertyName);
+        }
+    }
+
+    /**
+     * Setup ValueAnimator's values.
+     * This will handle all of the integer, float and color types.
+     *
+     * @param anim The target Animator which will be updated.
+     * @param arrayAnimator TypedArray for the ValueAnimator.
+     * @param getFloats True if the value type is float.
+     * @param hasFrom True if "valueFrom" exists.
+     * @param fromType The type of "valueFrom".
+     * @param hasTo True if "valueTo" exists.
+     * @param toType The type of "valueTo".
+     */
+    private static void setupValues(ValueAnimator anim, TypedArray arrayAnimator,
+            boolean getFloats, boolean hasFrom, int fromType, boolean hasTo, int toType) {
+        int valueFromIndex = R.styleable.Animator_valueFrom;
+        int valueToIndex = R.styleable.Animator_valueTo;
         if (getFloats) {
             float valueFrom;
             float valueTo;
@@ -296,63 +481,6 @@
                 }
             }
         }
-
-        anim.setDuration(duration);
-        anim.setStartDelay(startDelay);
-
-        if (arrayAnimator.hasValue(R.styleable.Animator_repeatCount)) {
-            anim.setRepeatCount(
-                    arrayAnimator.getInt(R.styleable.Animator_repeatCount, 0));
-        }
-        if (arrayAnimator.hasValue(R.styleable.Animator_repeatMode)) {
-            anim.setRepeatMode(
-                    arrayAnimator.getInt(R.styleable.Animator_repeatMode,
-                            ValueAnimator.RESTART));
-        }
-        if (evaluator != null) {
-            anim.setEvaluator(evaluator);
-        }
-
-        if (arrayObjectAnimator != null) {
-            ObjectAnimator oa = (ObjectAnimator) anim;
-            String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData);
-
-            // Note that if there is a pathData defined in the Object Animator,
-            // valueFrom / valueTo will be overwritten by the pathData.
-            if (pathData != null) {
-                String propertyXName =
-                        arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName);
-                String propertyYName =
-                        arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyYName);
-
-                if (propertyXName == null && propertyYName == null) {
-                    throw new IllegalArgumentException("propertyXName or propertyYName"
-                            + " is needed for PathData in Object Animator");
-                } else {
-                    Path path = PathParser.createPathFromPathData(pathData);
-                    Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, !getFloats);
-                    PropertyValuesHolder x = null;
-                    PropertyValuesHolder y = null;
-                    if (propertyXName != null) {
-                        x = PropertyValuesHolder.ofKeyframe(propertyXName, keyframes[0]);
-                    }
-                    if (propertyYName != null) {
-                        y = PropertyValuesHolder.ofKeyframe(propertyYName, keyframes[1]);
-                    }
-                    if (x == null) {
-                        oa.setValues(y);
-                    } else if (y == null) {
-                        oa.setValues(x);
-                    } else {
-                        oa.setValues(x, y);
-                    }
-                }
-            } else {
-                String propertyName =
-                        arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyName);
-                oa.setPropertyName(propertyName);
-            }
-        }
     }
 
     private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser)
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9132883..d0d0289 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -30,6 +30,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -5935,14 +5936,21 @@
     }
 
     /**
-     * Put this Activity in a mode where the user is locked to the
+     * Request to put this Activity in a mode where the user is locked to the
      * current task.
      *
      * This will prevent the user from launching other apps, going to settings,
      * or reaching the home screen.
      *
-     * Lock task mode will only start if the activity has been whitelisted by the
-     * Device Owner through DevicePolicyManager#setLockTaskComponents.
+     * If {@link DevicePolicyManager#isLockTaskPermitted(String)} returns true
+     * for this component then the app will go directly into Lock Task mode.  The user
+     * will not be able to exit this mode until {@link Activity#stopLockTask()} is called.
+     *
+     * If {@link DevicePolicyManager#isLockTaskPermitted(String)} returns false
+     * then the system will prompt the user with a dialog requesting permission to enter
+     * this mode.  When entered through this method the user can exit at any time by
+     * swiping down twice from the top of the screen.  Calling stopLockTask will also
+     * exit the mode.
      */
     public void startLockTask() {
         try {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 56462ae..572d389 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2145,6 +2145,13 @@
             return true;
         }
 
+        case START_LOCK_TASK_BY_CURRENT: {
+            data.enforceInterface(IActivityManager.descriptor);
+            startLockTaskModeOnCurrent();
+            reply.writeNoException();
+            return true;
+        }
+
         case STOP_LOCK_TASK_MODE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             stopLockTaskMode();
@@ -2152,6 +2159,13 @@
             return true;
         }
 
+        case STOP_LOCK_TASK_BY_CURRENT: {
+            data.enforceInterface(IActivityManager.descriptor);
+            stopLockTaskModeOnCurrent();
+            reply.writeNoException();
+            return true;
+        }
+
         case IS_IN_LOCK_TASK_MODE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final boolean isInLockTaskMode = isInLockTaskMode();
@@ -4947,6 +4961,17 @@
     }
 
     @Override
+    public void startLockTaskModeOnCurrent() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(START_LOCK_TASK_BY_CURRENT, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
     public void stopLockTaskMode() throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -4958,6 +4983,17 @@
     }
 
     @Override
+    public void stopLockTaskModeOnCurrent() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(STOP_LOCK_TASK_BY_CURRENT, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
     public boolean isInLockTaskMode() throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 9160452..0ecead9 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -29,8 +29,6 @@
 import android.view.Window;
 
 import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
 
 /**
  * Helper class for building an options Bundle that can be used with
@@ -398,14 +396,14 @@
                 if (sharedElementName == null) {
                     throw new IllegalArgumentException("Shared element name must not be null");
                 }
-                String viewName = sharedElement.first.getViewName();
-                if (viewName == null) {
+                String name = sharedElement.first.getTransitionName();
+                if (name == null) {
                     throw new IllegalArgumentException("Shared elements must have non-null " +
-                            "viewNames");
+                            "transitionNames");
                 }
 
                 names.add(sharedElementName);
-                mappedNames.add(viewName);
+                mappedNames.add(name);
             }
         }
 
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index c7030b0..c351cd5 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -233,6 +233,13 @@
         if (getViewsTransition() != null) {
             getDecor().captureTransitioningViews(mTransitioningViews);
             mTransitioningViews.removeAll(mSharedElements);
+            Rect r = new Rect();
+            for (int i = mTransitioningViews.size() - 1; i >= 0; i--) {
+                View view = mTransitioningViews.get(i);
+                if (!view.getGlobalVisibleRect(r)) {
+                    mTransitioningViews.remove(i);
+                }
+            }
         }
         setEpicenter();
     }
@@ -274,7 +281,7 @@
     public ArrayList<String> getMappedNames() {
         ArrayList<String> names = new ArrayList<String>(mSharedElements.size());
         for (int i = 0; i < mSharedElements.size(); i++) {
-            names.add(mSharedElements.get(i).getViewName());
+            names.add(mSharedElements.get(i).getTransitionName());
         }
         return names;
     }
@@ -351,9 +358,9 @@
                 String name = mAllSharedElementNames.get(i);
                 View sharedElement = sharedElements.get(name);
                 if (sharedElement != null) {
-                    if (sharedElement.getViewName() == null) {
+                    if (sharedElement.getTransitionName() == null) {
                         throw new IllegalArgumentException("Shared elements must have " +
-                                "non-null viewNames");
+                                "non-null transitionNames");
                     }
                     mSharedElementNames.add(name);
                     mSharedElements.add(sharedElement);
@@ -487,7 +494,7 @@
                 if (bitmap != null) {
                     snapshot.setBackground(new BitmapDrawable(resources, bitmap));
                 }
-                snapshot.setViewName(name);
+                snapshot.setTransitionName(name);
                 setSharedElementState(snapshot, name, state, parentLoc);
                 snapshots.add(snapshot);
             }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 5e17e1a..13b922c 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -48,11 +48,13 @@
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Display;
@@ -1469,6 +1471,18 @@
     /**
      * @hide
      */
+    public void addCrossProfileIntentsForPackage(String packageName,
+            int sourceUserId, int targetUserId) {
+        try {
+            mPM.addCrossProfileIntentsForPackage(packageName, sourceUserId, targetUserId);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
+    /**
+     * @hide
+     */
     @Override
     public void clearCrossProfileIntentFilters(int sourceUserId) {
         try {
@@ -1478,6 +1492,15 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public Bitmap getUserIcon(int userId) {
+        UserManager um = UserManager.get(mContext);
+        return um.getUserIcon(userId);
+    }
+
     private final ContextImpl mContext;
     private final IPackageManager mPM;
 
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 01a388f..4433a3a 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -581,13 +581,13 @@
 
     @Override
     public FragmentTransaction setSharedElement(View sharedElement, String name) {
-        String viewName = sharedElement.getViewName();
-        if (viewName == null) {
-            throw new IllegalArgumentException("Unique viewNames are required for all" +
+        String transitionName = sharedElement.getTransitionName();
+        if (transitionName == null) {
+            throw new IllegalArgumentException("Unique transitionNames are required for all" +
                     " sharedElements");
         }
         mSharedElementSourceNames = new ArrayList<String>(1);
-        mSharedElementSourceNames.add(viewName);
+        mSharedElementSourceNames.add(transitionName);
 
         mSharedElementTargetNames = new ArrayList<String>(1);
         mSharedElementTargetNames.add(name);
@@ -603,12 +603,12 @@
             ArrayList<String> sourceNames = new ArrayList<String>(sharedElements.length);
             ArrayList<String> targetNames = new ArrayList<String>(sharedElements.length);
             for (int i = 0; i < sharedElements.length; i++) {
-                String viewName = sharedElements[i].first.getViewName();
-                if (viewName == null) {
-                    throw new IllegalArgumentException("Unique viewNames are required for all" +
-                            " sharedElements");
+                String transitionName = sharedElements[i].first.getTransitionName();
+                if (transitionName == null) {
+                    throw new IllegalArgumentException("Unique transitionNames are required for all"
+                            + " sharedElements");
                 }
-                sourceNames.add(viewName);
+                sourceNames.add(transitionName);
                 targetNames.add(sharedElements[i].second);
             }
             mSharedElementSourceNames = sourceNames;
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 7479ecd..b6ea3c3 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -184,10 +184,10 @@
     /**
      * Used with {@link #setCustomTransition(int, int)} to map a View from a removed or hidden
      * Fragment to a View from a shown or added Fragment.
-     * <var>sharedElement</var> must have a unique viewName in the View hierarchy.
+     * <var>sharedElement</var> must have a unique transitionName in the View hierarchy.
      * @param sharedElement A View in a disappearing Fragment to match with a View in an
      *                      appearing Fragment.
-     * @param name The viewName for a View in an appearing Fragment to match to the shared
+     * @param name The transitionName for a View in an appearing Fragment to match to the shared
      *             element.
      */
     public abstract FragmentTransaction setSharedElement(View sharedElement, String name);
@@ -195,8 +195,8 @@
     /**
      * Used with {@link #setCustomTransition(int, int)} to map multiple Views from removed or hidden
      * Fragments to a Views from a shown or added Fragments. Views in
-     * <var>sharedElements</var> must have unique viewNames in the View hierarchy.
-     * @param sharedElements Pairs of Views in disappearing Fragments to viewNames in
+     * <var>sharedElements</var> must have unique transitionNames in the View hierarchy.
+     * @param sharedElements Pairs of Views in disappearing Fragments to transitionNames in
      *                       appearing Fragments.
      */
     public abstract FragmentTransaction setSharedElements(Pair<View, String>... sharedElements);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index bf2d7e5..b630278 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -429,6 +429,9 @@
     public IBinder getHomeActivityToken() throws RemoteException;
 
     /** @hide */
+    public void startLockTaskModeOnCurrent() throws RemoteException;
+
+    /** @hide */
     public void startLockTaskMode(int taskId) throws RemoteException;
 
     /** @hide */
@@ -438,6 +441,9 @@
     public void stopLockTaskMode() throws RemoteException;
 
     /** @hide */
+    public void stopLockTaskModeOnCurrent() throws RemoteException;
+
+    /** @hide */
     public boolean isInLockTaskMode() throws RemoteException;
 
     /** @hide */
@@ -744,4 +750,6 @@
     int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
     int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
     int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
+    int START_LOCK_TASK_BY_CURRENT = IBinder.FIRST_CALL_TRANSACTION+221;
+    int STOP_LOCK_TASK_BY_CURRENT = IBinder.FIRST_CALL_TRANSACTION+222;
 }
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index b78b9c9..c583998 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -188,6 +188,9 @@
             endPerformanceSnapshot();
         }
         if (mPerfMetrics != null) {
+            if (results == null) {
+                results = new Bundle();
+            }
             results.putAll(mPerfMetrics);
         }
         if (mUiAutomation != null) {
diff --git a/core/java/android/app/SharedElementListener.java b/core/java/android/app/SharedElementListener.java
index e03e42e..14fbfab 100644
--- a/core/java/android/app/SharedElementListener.java
+++ b/core/java/android/app/SharedElementListener.java
@@ -108,7 +108,7 @@
      * @param names The names of all shared elements transferred from the calling Activity
      *              to the started Activity.
      * @param sharedElements The mapping of shared element names to Views. The best guess
-     *                       will be filled into sharedElements based on the View names.
+     *                       will be filled into sharedElements based on the transitionNames.
      */
     public void remapSharedElements(List<String> names, Map<String, View> sharedElements) {}
 }
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 706ef04..4631323 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -31,12 +31,22 @@
  * @hide
  */
 public class BackupTransport {
+    // Zero return always means things are okay.  If returned from
+    // getNextFullRestoreDataChunk(), it means that no data could be delivered at
+    // this time, but the restore is still running and the caller should simply
+    // retry.
     public static final int TRANSPORT_OK = 0;
-    public static final int TRANSPORT_ERROR = 1;
-    public static final int TRANSPORT_NOT_INITIALIZED = 2;
-    public static final int TRANSPORT_PACKAGE_REJECTED = 3;
-    public static final int AGENT_ERROR = 4;
-    public static final int AGENT_UNKNOWN = 5;
+
+    // -1 is special; it is used in getNextFullRestoreDataChunk() to indicate that
+    // we've delivered the entire data stream for the current restore target.
+    public static final int NO_MORE_DATA = -1;
+
+    // Result codes that indicate real errors are negative and not -1
+    public static final int TRANSPORT_ERROR = -1000;
+    public static final int TRANSPORT_NOT_INITIALIZED = -1001;
+    public static final int TRANSPORT_PACKAGE_REJECTED = -1002;
+    public static final int AGENT_ERROR = -1003;
+    public static final int AGENT_UNKNOWN = -1004;
 
     IBackupTransport mBinderImpl = new TransportImpl();
     /** @hide */
@@ -370,11 +380,14 @@
      * @param socket The file descriptor that the transport will use for delivering the
      *    streamed archive.  The transport must close this socket in all cases when returning
      *    from this method.
-     * @return 0 when no more data for the current package is available.  A positive value
-     *    indicates the presence of that many bytes to be delivered to the app.  Any negative
-     *    return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
-     *    indicating a fatal error condition that precludes further restore operations
-     *    on the current dataset.
+     * @return {@link #NO_MORE_DATA} when no more data for the current package is available.
+     *    A positive value indicates the presence of that many bytes to be delivered to the app.
+     *    A value of zero indicates that no data was deliverable at this time, but the restore
+     *    is still running and the caller should retry.  {@link #TRANSPORT_PACKAGE_REJECTED}
+     *    means that the current package's restore operation should be aborted, but that
+     *    the transport itself is still in a good state and so a multiple-package restore
+     *    sequence can still be continued.  Any other negative return value is treated as a
+     *    fatal error condition that aborts all further restore operations on the current dataset.
      */
     public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
         return 0;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3dfa78b..e24dc84 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -55,6 +55,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -6821,72 +6822,12 @@
         if (other == null) {
             return false;
         }
-        if (mAction != other.mAction) {
-            if (mAction != null) {
-                if (!mAction.equals(other.mAction)) {
-                    return false;
-                }
-            } else {
-                if (!other.mAction.equals(mAction)) {
-                    return false;
-                }
-            }
-        }
-        if (mData != other.mData) {
-            if (mData != null) {
-                if (!mData.equals(other.mData)) {
-                    return false;
-                }
-            } else {
-                if (!other.mData.equals(mData)) {
-                    return false;
-                }
-            }
-        }
-        if (mType != other.mType) {
-            if (mType != null) {
-                if (!mType.equals(other.mType)) {
-                    return false;
-                }
-            } else {
-                if (!other.mType.equals(mType)) {
-                    return false;
-                }
-            }
-        }
-        if (mPackage != other.mPackage) {
-            if (mPackage != null) {
-                if (!mPackage.equals(other.mPackage)) {
-                    return false;
-                }
-            } else {
-                if (!other.mPackage.equals(mPackage)) {
-                    return false;
-                }
-            }
-        }
-        if (mComponent != other.mComponent) {
-            if (mComponent != null) {
-                if (!mComponent.equals(other.mComponent)) {
-                    return false;
-                }
-            } else {
-                if (!other.mComponent.equals(mComponent)) {
-                    return false;
-                }
-            }
-        }
-        if (mCategories != other.mCategories) {
-            if (mCategories != null) {
-                if (!mCategories.equals(other.mCategories)) {
-                    return false;
-                }
-            } else {
-                if (!other.mCategories.equals(mCategories)) {
-                    return false;
-                }
-            }
-        }
+        if (!Objects.equals(this.mAction, other.mAction)) return false;
+        if (!Objects.equals(this.mData, other.mData)) return false;
+        if (!Objects.equals(this.mType, other.mType)) return false;
+        if (!Objects.equals(this.mPackage, other.mPackage)) return false;
+        if (!Objects.equals(this.mComponent, other.mComponent)) return false;
+        if (!Objects.equals(this.mCategories, other.mCategories)) return false;
 
         return true;
     }
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index abc8cde..bcf1e87 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -252,6 +252,13 @@
      */
     public static final int FLAG_IMMERSIVE = 0x0800;
     /**
+     * Bit in {@link #flags}: If set, a task rooted at this activity will have its
+     * baseIntent replaced by the activity immediately above this. Each activity may further
+     * relinquish its identity to the activity above it using this flag. Set from the
+     * android.R.attr#relinquishTaskIdentity attribute.
+     */
+    public static final int FLAG_RELINQUISH_TASK_IDENTITY = 0x1000;
+    /**
      * Bit in {@link #flags} indicating that tasks started with this activity are to be
      * removed from the recent list of tasks when the last activity in the task is finished.
      * {@link android.R.attr#autoRemoveFromRecents}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 00e7918..6111b01 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -251,6 +251,9 @@
     void addCrossProfileIntentFilter(in IntentFilter intentFilter, int sourceUserId, int targetUserId,
             int flags);
 
+    void addCrossProfileIntentsForPackage(in String packageName, int sourceUserId,
+            int targetUserId);
+
     void clearCrossProfileIntentFilters(int sourceUserId);
 
     /**
@@ -438,7 +441,7 @@
             int flags, in String installerPackageName,
             in VerificationParams verificationParams,
             in ContainerEncryptionParams encryptionParams,
-	    in String packageAbiOverride);
+        in String packageAbiOverride);
 
     int installExistingPackageAsUser(String packageName, int userId);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9d871c5..d11698c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -29,6 +29,7 @@
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Environment;
@@ -3610,4 +3611,16 @@
      * @hide
      */
     public abstract void clearCrossProfileIntentFilters(int sourceUserId);
+
+    /**
+     * Forwards all intents for {@link packageName} for user {@link sourceUserId} to user
+     * {@link targetUserId}.
+     * @hide
+     */
+    public abstract void addCrossProfileIntentsForPackage(String packageName,
+            int sourceUserId, int targetUserId);
+    /**
+     * @hide
+     */
+    public abstract Bitmap getUserIcon(int userId);
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0b336d0..b40a441 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2629,6 +2629,12 @@
                     false)) {
                 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
             }
+
+            if (sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
+                    false)) {
+                a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+            }
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 1ff41c0..1f9d60c 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -19,8 +19,11 @@
 import android.content.ComponentName;
 import android.content.IntentFilter;
 import android.graphics.drawable.Drawable;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Printer;
 import android.util.Slog;
@@ -127,6 +130,18 @@
     public String resolvePackageName;
 
     /**
+     * If not equal to UserHandle.USER_CURRENT, then the intent will be forwarded to this user.
+     * @hide
+     */
+    public int targetUserId;
+
+    /**
+     * If true, then loadIcon will return the icon of the target user.
+     * @hide
+     */
+    public boolean showTargetUserIcon;
+
+    /**
      * @hide Target comes from system process?
      */
     public boolean system;
@@ -202,6 +217,10 @@
                 return dr;
             }
         }
+        if (showTargetUserIcon) {
+            Bitmap bm = pm.getUserIcon(targetUserId);
+            return new BitmapDrawable(bm);
+        }
         return ci.loadIcon(pm);
     }
     
@@ -215,7 +234,9 @@
     public final int getIconResource() {
         if (icon != 0) return icon;
         final ComponentInfo ci = getComponentInfo();
-        if (ci != null) return ci.getIconResource();
+        if (ci != null && !showTargetUserIcon) {
+            return ci.getIconResource();
+        }
         return 0;
     }
 
@@ -250,6 +271,7 @@
     }
     
     public ResolveInfo() {
+        targetUserId = UserHandle.USER_CURRENT;
     }
 
     public ResolveInfo(ResolveInfo orig) {
@@ -266,6 +288,7 @@
         icon = orig.icon;
         resolvePackageName = orig.resolvePackageName;
         system = orig.system;
+        targetUserId = orig.targetUserId;
     }
 
     public String toString() {
@@ -285,6 +308,13 @@
         }
         sb.append(" m=0x");
         sb.append(Integer.toHexString(match));
+        if (targetUserId != UserHandle.USER_CURRENT) {
+            sb.append(" targetUserId=");
+            sb.append(targetUserId);
+        }
+        if (showTargetUserIcon) {
+            sb.append(" [showTargetUserIcon]");
+        }
         sb.append('}');
         return sb.toString();
     }
@@ -320,6 +350,8 @@
         TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags);
         dest.writeInt(icon);
         dest.writeString(resolvePackageName);
+        dest.writeInt(targetUserId);
+        dest.writeInt(showTargetUserIcon ? 1 : 0);
         dest.writeInt(system ? 1 : 0);
     }
 
@@ -363,6 +395,8 @@
                 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
         icon = source.readInt();
         resolvePackageName = source.readString();
+        targetUserId = source.readInt();
+        showTargetUserIcon = source.readInt() != 0;
         system = source.readInt() != 0;
     }
     
@@ -374,6 +408,13 @@
         }
 
         public final int compare(ResolveInfo a, ResolveInfo b) {
+            // We want to put the one targeted to another user at the end of the dialog.
+            if (a.targetUserId != UserHandle.USER_CURRENT) {
+                return 1;
+            }
+            if (b.targetUserId != UserHandle.USER_CURRENT) {
+                return -1;
+            }
             CharSequence  sa = a.loadLabel(mPM);
             if (sa == null) sa = a.activityInfo.name;
             CharSequence  sb = b.loadLabel(mPM);
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 20dcf83..d2146ac 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -885,9 +885,9 @@
 
     /**
      * Extracts theme attributes from a typed array for later resolution using
-     * {@link Theme#resolveAttributes(int[], int[])}. Removes the entries from
-     * the typed array so that subsequent calls to typed getters will return the
-     * default value without crashing.
+     * {@link android.content.res.Resources.Theme#resolveAttributes(int[], int[])}.
+     * Removes the entries from the typed array so that subsequent calls to typed
+     * getters will return the default value without crashing.
      *
      * @return an array of length {@link #getIndexCount()} populated with theme
      *         attributes, or null if there are no theme attributes in the typed
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 44fc3b6..cc8503b 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -167,7 +167,7 @@
     private boolean mOneShot;
     private boolean mWithBuffer;
     private boolean mFaceDetectionRunning = false;
-    private Object mAutoFocusCallbackLock = new Object();
+    private final Object mAutoFocusCallbackLock = new Object();
 
     private static final int NO_ERROR = 0;
     private static final int EACCESS = -13;
@@ -202,14 +202,14 @@
 
     /**
      * A constant meaning the normal camera connect/open will be used.
-     * @hide
      */
-    public static final int CAMERA_HAL_API_VERSION_NORMAL_OPEN = -2;
+    private static final int CAMERA_HAL_API_VERSION_NORMAL_CONNECT = -2;
 
     /**
      * Used to indicate HAL version un-specified.
      */
     private static final int CAMERA_HAL_API_VERSION_UNSPECIFIED = -1;
+
     /**
      * Hardware face detection. It does not use much CPU.
      */
@@ -376,18 +376,25 @@
      *
      * @param cameraId The hardware camera to access, between 0 and
      * {@link #getNumberOfCameras()}-1.
-     * @param halVersion The HAL API version this camera device to be opened as. When
-     * it is {@value #CAMERA_HAL_API_VERSION_NORMAL_OPEN}, the methods will be equivalent
-     * to {@link #open}, but more detailed error information will be returned to managed code.
+     * @param halVersion The HAL API version this camera device to be opened as.
      * @return a new Camera object, connected, locked and ready for use.
+     *
+     * @throws IllegalArgumentException if the {@code halVersion} is invalid
+     *
      * @throws RuntimeException if opening the camera fails (for example, if the
      * camera is in use by another process or device policy manager has disabled
      * the camera).
+     *
      * @see android.app.admin.DevicePolicyManager#getCameraDisabled(android.content.ComponentName)
+     * @see #CAMERA_HAL_API_VERSION_1_0
      *
      * @hide
      */
     public static Camera openLegacy(int cameraId, int halVersion) {
+        if (halVersion < CAMERA_HAL_API_VERSION_1_0) {
+            throw new IllegalArgumentException("Invalid HAL version " + halVersion);
+        }
+
         return new Camera(cameraId, halVersion);
     }
 
@@ -399,7 +406,7 @@
      * @param halVersion The HAL API version this camera device to be opened as.
      */
     private Camera(int cameraId, int halVersion) {
-        int err = cameraInit(cameraId, halVersion);
+        int err = cameraInitVersion(cameraId, halVersion);
         if (checkInitErrors(err)) {
             switch(err) {
                 case EACCESS:
@@ -428,13 +435,7 @@
         }
     }
 
-    private int cameraInit(int cameraId, int halVersion) {
-        // This function should be only called by Camera(int cameraId, int halVersion).
-        if (halVersion < CAMERA_HAL_API_VERSION_1_0 &&
-                halVersion != CAMERA_HAL_API_VERSION_NORMAL_OPEN) {
-            throw new IllegalArgumentException("Invalid HAL version " + halVersion);
-        }
-
+    private int cameraInitVersion(int cameraId, int halVersion) {
         mShutterCallback = null;
         mRawImageCallback = null;
         mJpegCallback = null;
@@ -457,8 +458,31 @@
         return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
     }
 
+    private int cameraInitNormal(int cameraId) {
+        return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
+    }
+
+    /**
+     * Connect to the camera service using #connectLegacy
+     *
+     * <p>
+     * This acts the same as normal except that it will return
+     * the detailed error code if open fails instead of
+     * converting everything into {@code NO_INIT}.</p>
+     *
+     * <p>Intended to use by the camera2 shim only, do <i>not</i> use this for other code.</p>
+     *
+     * @return a detailed errno error code, or {@code NO_ERROR} on success
+     *
+     * @hide
+     */
+    public int cameraInitUnspecified(int cameraId) {
+        return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_UNSPECIFIED);
+    }
+
+    /** used by Camera#open, Camera#open(int) */
     Camera(int cameraId) {
-        int err = cameraInit(cameraId);
+        int err = cameraInitNormal(cameraId);
         if (checkInitErrors(err)) {
             switch(err) {
                 case EACCESS:
@@ -472,32 +496,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
-    public int cameraInit(int cameraId) {
-        mShutterCallback = null;
-        mRawImageCallback = null;
-        mJpegCallback = null;
-        mPreviewCallback = null;
-        mPostviewCallback = null;
-        mUsingPreviewAllocation = false;
-        mZoomListener = null;
-
-        Looper looper;
-        if ((looper = Looper.myLooper()) != null) {
-            mEventHandler = new EventHandler(this, looper);
-        } else if ((looper = Looper.getMainLooper()) != null) {
-            mEventHandler = new EventHandler(this, looper);
-        } else {
-            mEventHandler = null;
-        }
-
-        String packageName = ActivityThread.currentPackageName();
-
-        return native_setup(new WeakReference<Camera>(this), cameraId,
-                CAMERA_HAL_API_VERSION_UNSPECIFIED, packageName);
-    }
 
     /**
      * @hide
@@ -519,6 +517,7 @@
     Camera() {
     }
 
+    @Override
     protected void finalize() {
         release();
     }
@@ -1056,7 +1055,7 @@
 
     private class EventHandler extends Handler
     {
-        private Camera mCamera;
+        private final Camera mCamera;
 
         public EventHandler(Camera c, Looper looper) {
             super(looper);
@@ -2337,6 +2336,7 @@
          * @hide
          * @deprecated
          */
+        @Deprecated
         public void dump() {
             Log.e(TAG, "dump: size=" + mMap.size());
             for (String k : mMap.keySet()) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 4a87680..e2f88eb 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -579,6 +579,7 @@
      * of the lens that can be focused correctly.</p>
      * <p>If the lens is fixed-focus, this should be
      * 0.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      */
     public static final Key<Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE =
             new Key<Float>("android.lens.info.minimumFocusDistance", float.class);
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 73188ff..9a3d806 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -278,14 +278,19 @@
                 ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
                 int id = Integer.parseInt(cameraId);
                 try {
-                    mCameraService.connectDevice(callbacks, id, mContext.getPackageName(),
-                            USE_CALLING_UID, holder);
-                    cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
-                } catch (CameraRuntimeException e) {
-                    if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
+                    if (supportsCamera2Api(cameraId)) {
+                        // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
+                        mCameraService.connectDevice(callbacks, id, mContext.getPackageName(),
+                                USE_CALLING_UID, holder);
+                        cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+                    } else {
                         // Use legacy camera implementation for HAL1 devices
                         Log.i(TAG, "Using legacy camera HAL.");
                         cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
+                    }
+                } catch (CameraRuntimeException e) {
+                    if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
+                        throw new AssertionError("Should've gone down the shim path");
                     } else if (e.getReason() == CameraAccessException.CAMERA_IN_USE ||
                             e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE ||
                             e.getReason() == CameraAccessException.CAMERA_DISABLED ||
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index de1d9a3..2e59eee 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -460,7 +460,7 @@
      * starting and stopping repeating request and flushing.
      *
      * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
-     * sent to HAL. Then onCaptureSequenceCompleted is immediately triggered.
+     * sent to HAL. Then onCaptureSequenceAborted is immediately triggered.
      * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
      * is added to the list mFrameNumberRequestPairs.</p>
      *
@@ -471,7 +471,7 @@
     private void checkEarlyTriggerSequenceComplete(
             final int requestId, final long lastFrameNumber) {
         // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
-        // was never sent to HAL. Should trigger onCaptureSequenceCompleted immediately.
+        // was never sent to HAL. Should trigger onCaptureSequenceAborted immediately.
         if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
             final CaptureListenerHolder holder;
             int index = mCaptureListenerMap.indexOfKey(requestId);
@@ -488,7 +488,7 @@
 
             if (holder != null) {
                 if (DEBUG) {
-                    Log.v(TAG, "immediately trigger onCaptureSequenceCompleted because"
+                    Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
                             + " request did not reach HAL");
                 }
 
@@ -505,10 +505,9 @@
                                     || lastFrameNumber > Integer.MAX_VALUE) {
                                 throw new AssertionError(lastFrameNumber + " cannot be cast to int");
                             }
-                            holder.getListener().onCaptureSequenceCompleted(
+                            holder.getListener().onCaptureSequenceAborted(
                                     CameraDeviceImpl.this,
-                                    requestId,
-                                    lastFrameNumber);
+                                    requestId);
                         }
                     }
                 };
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index e4412ce..abd69c1 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -76,13 +76,11 @@
         }
         // TODO: Move open/init into LegacyCameraDevice thread when API is switched to async.
         Camera legacyCamera = Camera.openUninitialized();
-        int initErrors = legacyCamera.cameraInit(cameraId);
+        int initErrors = legacyCamera.cameraInitUnspecified(cameraId);
+
         // Check errors old HAL initialization
-        if (Camera.checkInitErrors(initErrors)) {
-            // TODO: Map over old camera error codes.  This likely involves improving the error
-            // reporting in the HAL1 connect path.
-            throw new CameraRuntimeException(CameraAccessException.CAMERA_DISCONNECTED);
-        }
+        CameraBinderDecorator.throwOnError(initErrors);
+
         LegacyCameraDevice device = new LegacyCameraDevice(cameraId, legacyCamera, callbacks);
         return new CameraDeviceUserShim(cameraId, device);
     }
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 7f23561..1cde2c4 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -48,6 +48,9 @@
     private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
     private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
 
+    // for metadata
+    private static final float LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS = 0.0f;
+
     private static final long APPROXIMATE_CAPTURE_DELAY_MS = 200; // ms
     private static final long APPROXIMATE_SENSOR_AREA = (1 << 23); // 8mp
     private static final long APPROXIMATE_JPEG_ENCODE_TIME = 600; // ms
@@ -94,10 +97,12 @@
     }
 
     private static void mapCameraParameters(CameraMetadataNative m, Camera.Parameters p) {
+        m.set(INFO_SUPPORTED_HARDWARE_LEVEL, INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED);
         mapStreamConfigs(m, p);
         mapAeConfig(m, p);
         mapCapabilities(m, p);
-
+        mapLens(m, p);
+        mapFlash(m, p);
         // TODO: map other fields
     }
 
@@ -200,6 +205,30 @@
         m.set(REQUEST_AVAILABLE_CAPABILITIES, capabilities);
     }
 
+    private static void mapLens(CameraMetadataNative m, Camera.Parameters p) {
+        /*
+         *  We can tell if the lens is fixed focus;
+         *  but if it's not, we can't tell the minimum focus distance, so leave it null then.
+         */
+        if (p.getFocusMode() == Camera.Parameters.FOCUS_MODE_FIXED) {
+            m.set(LENS_INFO_MINIMUM_FOCUS_DISTANCE, LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS);
+        }
+    }
+
+    private static void mapFlash(CameraMetadataNative m, Camera.Parameters p) {
+        boolean flashAvailable = false;
+        List<String> supportedFlashModes = p.getSupportedFlashModes();
+        if (supportedFlashModes != null) {
+            // If only 'OFF' is available, we don't really have flash support
+            if (!(supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_OFF) &&
+                    supportedFlashModes.size() == 1)) {
+                flashAvailable = true;
+            }
+        }
+
+        m.set(FLASH_INFO_AVAILABLE, flashAvailable);
+    }
+
     private static void appendStreamConfig(
             ArrayList<StreamConfiguration> configs, int format, List<Camera.Size> sizes) {
         for (Camera.Size size : sizes) {
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 559a469..73726fa4 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -21,6 +21,7 @@
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.hdmi.IHdmiDeviceEventListener;
 import android.hardware.hdmi.IHdmiHotplugEventListener;
+import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
 
 import java.util.List;
 
@@ -42,4 +43,9 @@
     void portSelect(int portId, IHdmiControlCallback callback);
     void sendKeyEvent(int keyCode, boolean isPressed);
     List<HdmiPortInfo> getPortInfo();
+    boolean canChangeSystemAudioMode();
+    boolean getSystemAudioMode();
+    void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback);
+    void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
+    void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl b/core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl
new file mode 100644
index 0000000..714bbe7
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.hardware.hdmi;
+
+/**
+ * Callback interface definition for HDMI client to get informed of
+ * "System Audio" mode change.
+ *
+ * @hide
+ */
+oneway interface IHdmiSystemAudioModeChangeListener {
+
+    /**
+     * @param enabled true if the device gets activated
+     */
+    void onStatusChanged(in boolean enabled);
+}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 9218c11..53e87a6 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -25,6 +25,7 @@
 import android.nfc.INfcAdapterExtras;
 import android.nfc.INfcTag;
 import android.nfc.INfcCardEmulation;
+import android.nfc.INfcLockscreenDispatch;
 import android.os.Bundle;
 
 /**
@@ -52,4 +53,6 @@
 
     void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
     void setP2pModes(int initatorModes, int targetModes);
+
+    void registerLockscreenDispatch(INfcLockscreenDispatch lockscreenDispatch, in int[] techList);
 }
diff --git a/core/java/android/nfc/INfcLockscreenDispatch.aidl b/core/java/android/nfc/INfcLockscreenDispatch.aidl
new file mode 100644
index 0000000..27e9a8c
--- /dev/null
+++ b/core/java/android/nfc/INfcLockscreenDispatch.aidl
@@ -0,0 +1,12 @@
+package android.nfc;
+
+import android.nfc.Tag;
+
+/**
+ * @hide
+ */
+interface INfcLockscreenDispatch {
+
+    boolean onTagDetected(in Tag tag);
+
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index dd8e41c..be098a8 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -380,6 +380,16 @@
         public Uri[] createBeamUris(NfcEvent event);
     }
 
+
+    /**
+     * A callback to be invoked when an application has registered for receiving
+     * tags at the lockscreen.
+     */
+    public interface NfcLockscreenDispatch {
+        public boolean onTagDetected(Tag tag);
+    }
+
+
     /**
      * Helper to check if this device has FEATURE_NFC, but without using
      * a context.
@@ -1417,6 +1427,26 @@
         }
     }
 
+    public boolean registerLockscreenDispatch(final NfcLockscreenDispatch lockscreenDispatch,
+                                           String[] techList) {
+        try {
+            sService.registerLockscreenDispatch(new INfcLockscreenDispatch.Stub() {
+                @Override
+                public boolean onTagDetected(Tag tag) throws RemoteException {
+                    return lockscreenDispatch.onTagDetected(tag);
+                }
+            }, Tag.techListFromStrings(techList));
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Unable to register LockscreenDispatch", e);
+            return false;
+        }
+
+        return true;
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 0d261d1..43be702 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -35,6 +35,7 @@
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.HashMap;
 
 /**
  * Represents an NFC tag that has been discovered.
@@ -195,6 +196,41 @@
         return strings;
     }
 
+    static int[] techListFromStrings(String[] techStringList) throws IllegalArgumentException {
+        if (techStringList == null) {
+            throw new IllegalArgumentException("List cannot be null");
+        }
+        int[] techIntList = new int[techStringList.length];
+        HashMap<String, Integer> stringToCodeMap = getTechStringToCodeMap();
+        for (int i = 0; i < techStringList.length; i++) {
+            Integer code = stringToCodeMap.get(techStringList[i]);
+
+            if (code == null) {
+                throw new IllegalArgumentException("Unknown tech type " + techStringList[i]);
+            }
+
+            techIntList[i] = code.intValue();
+        }
+        return techIntList;
+    }
+
+    private static HashMap<String, Integer> getTechStringToCodeMap() {
+        HashMap<String, Integer> techStringToCodeMap = new HashMap<String, Integer>();
+
+        techStringToCodeMap.put(IsoDep.class.getName(), TagTechnology.ISO_DEP);
+        techStringToCodeMap.put(MifareClassic.class.getName(), TagTechnology.MIFARE_CLASSIC);
+        techStringToCodeMap.put(MifareUltralight.class.getName(), TagTechnology.MIFARE_ULTRALIGHT);
+        techStringToCodeMap.put(Ndef.class.getName(), TagTechnology.NDEF);
+        techStringToCodeMap.put(NdefFormatable.class.getName(), TagTechnology.NDEF_FORMATABLE);
+        techStringToCodeMap.put(NfcA.class.getName(), TagTechnology.NFC_A);
+        techStringToCodeMap.put(NfcB.class.getName(), TagTechnology.NFC_B);
+        techStringToCodeMap.put(NfcF.class.getName(), TagTechnology.NFC_F);
+        techStringToCodeMap.put(NfcV.class.getName(), TagTechnology.NFC_V);
+        techStringToCodeMap.put(NfcBarcode.class.getName(), TagTechnology.NFC_BARCODE);
+
+        return techStringToCodeMap;
+    }
+
     /**
      * For use by NfcService only.
      * @hide
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e627d49..f7d2bfd 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -171,6 +171,10 @@
     private static final String DATA_CONNECTION_COUNT_DATA = "dcc";
     private static final String WIFI_STATE_TIME_DATA = "wst";
     private static final String WIFI_STATE_COUNT_DATA = "wsc";
+    private static final String WIFI_SUPPL_STATE_TIME_DATA = "wsst";
+    private static final String WIFI_SUPPL_STATE_COUNT_DATA = "wssc";
+    private static final String WIFI_SIGNAL_STRENGTH_TIME_DATA = "wsgt";
+    private static final String WIFI_SIGNAL_STRENGTH_COUNT_DATA = "wsgc";
     private static final String BLUETOOTH_STATE_TIME_DATA = "bst";
     private static final String BLUETOOTH_STATE_COUNT_DATA = "bsc";
     private static final String POWER_USE_SUMMARY_DATA = "pws";
@@ -563,8 +567,8 @@
         public static final int STATE_BRIGHTNESS_SHIFT = 0;
         public static final int STATE_BRIGHTNESS_MASK = 0x7;
         // Constants from SIGNAL_STRENGTH_*
-        public static final int STATE_SIGNAL_STRENGTH_SHIFT = 3;
-        public static final int STATE_SIGNAL_STRENGTH_MASK = 0x7 << STATE_SIGNAL_STRENGTH_SHIFT;
+        public static final int STATE_PHONE_SIGNAL_STRENGTH_SHIFT = 3;
+        public static final int STATE_PHONE_SIGNAL_STRENGTH_MASK = 0x7 << STATE_PHONE_SIGNAL_STRENGTH_SHIFT;
         // Constants from ServiceState.STATE_*
         public static final int STATE_PHONE_STATE_SHIFT = 6;
         public static final int STATE_PHONE_STATE_MASK = 0x7 << STATE_PHONE_STATE_SHIFT;
@@ -582,7 +586,6 @@
         public static final int STATE_WIFI_SCAN_FLAG = 1<<27;
         public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26;
         public static final int STATE_MOBILE_RADIO_ACTIVE_FLAG = 1<<25;
-        public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
         // These are on the lower bits used for the command; if they change
         // we need to write another int of data.
         public static final int STATE_SENSOR_ON_FLAG = 1<<23;
@@ -591,17 +594,30 @@
         public static final int STATE_SCREEN_ON_FLAG = 1<<20;
         public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<19;
         public static final int STATE_PHONE_IN_CALL_FLAG = 1<<18;
-        public static final int STATE_WIFI_ON_FLAG = 1<<17;
         public static final int STATE_BLUETOOTH_ON_FLAG = 1<<16;
 
         public static final int MOST_INTERESTING_STATES =
             STATE_BATTERY_PLUGGED_FLAG | STATE_SCREEN_ON_FLAG
-            | STATE_GPS_ON_FLAG | STATE_PHONE_IN_CALL_FLAG;
+            | STATE_PHONE_IN_CALL_FLAG | STATE_BLUETOOTH_ON_FLAG;
 
         public int states;
 
-        public static final int STATE2_VIDEO_ON_FLAG = 1<<0;
-        public static final int STATE2_LOW_POWER_FLAG = 1<<1;
+        // Constants from WIFI_SUPPL_STATE_*
+        public static final int STATE2_WIFI_SUPPL_STATE_SHIFT = 0;
+        public static final int STATE2_WIFI_SUPPL_STATE_MASK = 0xf;
+        // Values for NUM_WIFI_SIGNAL_STRENGTH_BINS
+        public static final int STATE2_WIFI_SIGNAL_STRENGTH_SHIFT = 4;
+        public static final int STATE2_WIFI_SIGNAL_STRENGTH_MASK =
+                0x7 << STATE2_WIFI_SIGNAL_STRENGTH_SHIFT;
+
+        public static final int STATE2_LOW_POWER_FLAG = 1<<31;
+        public static final int STATE2_VIDEO_ON_FLAG = 1<<30;
+        public static final int STATE2_WIFI_RUNNING_FLAG = 1<<29;
+        public static final int STATE2_WIFI_ON_FLAG = 1<<28;
+
+        public static final int MOST_INTERESTING_STATES2 =
+            STATE2_LOW_POWER_FLAG | STATE2_WIFI_ON_FLAG;
+
         public int states2;
 
         // The wake lock that was acquired at this point.
@@ -1005,7 +1021,7 @@
     };
 
     public static final int NUM_SCREEN_BRIGHTNESS_BINS = 5;
-    
+
     /**
      * Returns the time in microseconds that the screen has been on with
      * the given brightness
@@ -1153,6 +1169,34 @@
      */
     public abstract int getPhoneDataConnectionCount(int dataType, int which);
 
+    public static final int WIFI_SUPPL_STATE_INVALID = 0;
+    public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1;
+    public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2;
+    public static final int WIFI_SUPPL_STATE_INACTIVE = 3;
+    public static final int WIFI_SUPPL_STATE_SCANNING = 4;
+    public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5;
+    public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6;
+    public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7;
+    public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8;
+    public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9;
+    public static final int WIFI_SUPPL_STATE_COMPLETED = 10;
+    public static final int WIFI_SUPPL_STATE_DORMANT = 11;
+    public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12;
+
+    public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED+1;
+
+    static final String[] WIFI_SUPPL_STATE_NAMES = {
+        "invalid", "disconn", "disabled", "inactive", "scanning",
+        "authenticating", "associating", "associated", "4-way-handshake",
+        "group-handshake", "completed", "dormant", "uninit"
+    };
+
+    static final String[] WIFI_SUPPL_STATE_SHORT_NAMES = {
+        "inv", "dsc", "dis", "inact", "scan",
+        "auth", "ascing", "asced", "4-way",
+        "group", "compl", "dorm", "uninit"
+    };
+
     public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS
             = new BitDescription[] {
         new BitDescription(HistoryItem.STATE_CPU_RUNNING_FLAG, "running", "r"),
@@ -1163,13 +1207,11 @@
         new BitDescription(HistoryItem.STATE_WIFI_SCAN_FLAG, "wifi_scan", "Ws"),
         new BitDescription(HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG, "wifi_multicast", "Wm"),
         new BitDescription(HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG, "mobile_radio", "Pr"),
-        new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
         new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
         new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio", "a"),
         new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
         new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
         new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
-        new BitDescription(HistoryItem.STATE_WIFI_ON_FLAG, "wifi", "W"),
         new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
         new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
                 HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
@@ -1178,11 +1220,10 @@
                 HistoryItem.STATE_PHONE_STATE_SHIFT, "phone_state", "Pst",
                 new String[] {"in", "out", "emergency", "off"},
                 new String[] {"in", "out", "em", "off"}),
-        new BitDescription(HistoryItem.STATE_SIGNAL_STRENGTH_MASK,
-                HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT, "signal_strength", "Pss",
-                SignalStrength.SIGNAL_STRENGTH_NAMES, new String[] {
-                    "0", "1", "2", "3", "4"
-        }),
+        new BitDescription(HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK,
+                HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT, "phone_signal_strength", "Pss",
+                SignalStrength.SIGNAL_STRENGTH_NAMES,
+                new String[] { "0", "1", "2", "3", "4" }),
         new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
                 HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
                 SCREEN_BRIGHTNESS_NAMES, SCREEN_BRIGHTNESS_SHORT_NAMES),
@@ -1190,8 +1231,17 @@
 
     public static final BitDescription[] HISTORY_STATE2_DESCRIPTIONS
             = new BitDescription[] {
-        new BitDescription(HistoryItem.STATE2_VIDEO_ON_FLAG, "video", "v"),
         new BitDescription(HistoryItem.STATE2_LOW_POWER_FLAG, "low_power", "lp"),
+        new BitDescription(HistoryItem.STATE2_VIDEO_ON_FLAG, "video", "v"),
+        new BitDescription(HistoryItem.STATE2_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
+        new BitDescription(HistoryItem.STATE2_WIFI_ON_FLAG, "wifi", "W"),
+        new BitDescription(HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK,
+                HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT, "wifi_signal_strength", "Wss",
+                new String[] { "0", "1", "2", "3", "4" },
+                new String[] { "0", "1", "2", "3", "4" }),
+        new BitDescription(HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK,
+                HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT, "wifi_suppl", "Wsp",
+                WIFI_SUPPL_STATE_NAMES, WIFI_SUPPL_STATE_SHORT_NAMES),
     };
 
     public static final String[] HISTORY_EVENT_NAMES = new String[] {
@@ -1250,6 +1300,40 @@
     public abstract int getWifiStateCount(int wifiState, int which);
 
     /**
+     * Returns the time in microseconds that the wifi supplicant has been
+     * in a given state.
+     *
+     * {@hide}
+     */
+    public abstract long getWifiSupplStateTime(int state, long elapsedRealtimeUs, int which);
+
+    /**
+     * Returns the number of times that the wifi supplicant has transitioned
+     * to a given state.
+     *
+     * {@hide}
+     */
+    public abstract int getWifiSupplStateCount(int state, int which);
+
+    public static final int NUM_WIFI_SIGNAL_STRENGTH_BINS = 5;
+
+    /**
+     * Returns the time in microseconds that WIFI has been running with
+     * the given signal strength.
+     *
+     * {@hide}
+     */
+    public abstract long getWifiSignalStrengthTime(int strengthBin,
+            long elapsedRealtimeUs, int which);
+
+    /**
+     * Returns the number of times WIFI has entered the given signal strength.
+     *
+     * {@hide}
+     */
+    public abstract int getWifiSignalStrengthCount(int strengthBin, int which);
+
+    /**
      * Returns the time in microseconds that bluetooth has been on while the device was
      * running on battery.
      * 
@@ -1780,6 +1864,28 @@
         }
         dumpLine(pw, 0 /* uid */, category, WIFI_STATE_COUNT_DATA, args);
 
+        // Dump wifi suppl state stats
+        args = new Object[NUM_WIFI_SUPPL_STATES];
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            args[i] = getWifiSupplStateTime(i, rawRealtime, which) / 1000;
+        }
+        dumpLine(pw, 0 /* uid */, category, WIFI_SUPPL_STATE_TIME_DATA, args);
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            args[i] = getWifiSupplStateCount(i, which);
+        }
+        dumpLine(pw, 0 /* uid */, category, WIFI_SUPPL_STATE_COUNT_DATA, args);
+
+        // Dump wifi signal strength stats
+        args = new Object[NUM_WIFI_SIGNAL_STRENGTH_BINS];
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            args[i] = getWifiSignalStrengthTime(i, rawRealtime, which) / 1000;
+        }
+        dumpLine(pw, 0 /* uid */, category, WIFI_SIGNAL_STRENGTH_TIME_DATA, args);
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            args[i] = getWifiSignalStrengthCount(i, which);
+        }
+        dumpLine(pw, 0 /* uid */, category, WIFI_SIGNAL_STRENGTH_COUNT_DATA, args);
+
         // Dump bluetooth state stats
         args = new Object[NUM_BLUETOOTH_STATES];
         for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
@@ -2254,7 +2360,7 @@
                 pw.print(", sent "); pw.print(mobileTxTotalPackets); pw.println(")");
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Signal levels:");
+        sb.append("  Phone signal levels:");
         didOne = false;
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             final long time = getPhoneSignalStrengthTime(i, rawRealtime, which);
@@ -2372,7 +2478,55 @@
             sb.append("(");
             sb.append(formatRatioLocked(time, whichBatteryRealtime));
             sb.append(") ");
-            sb.append(getPhoneDataConnectionCount(i, which));
+            sb.append(getWifiStateCount(i, which));
+            sb.append("x");
+        }
+        if (!didOne) sb.append(" (no activity)");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Wifi supplicant states:");
+        didOne = false;
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            final long time = getWifiSupplStateTime(i, rawRealtime, which);
+            if (time == 0) {
+                continue;
+            }
+            sb.append("\n    ");
+            didOne = true;
+            sb.append(WIFI_SUPPL_STATE_NAMES[i]);
+            sb.append(" ");
+            formatTimeMs(sb, time/1000);
+            sb.append("(");
+            sb.append(formatRatioLocked(time, whichBatteryRealtime));
+            sb.append(") ");
+            sb.append(getWifiSupplStateCount(i, which));
+            sb.append("x");
+        }
+        if (!didOne) sb.append(" (no activity)");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Wifi signal levels:");
+        didOne = false;
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            final long time = getWifiSignalStrengthTime(i, rawRealtime, which);
+            if (time == 0) {
+                continue;
+            }
+            sb.append("\n    ");
+            sb.append(prefix);
+            didOne = true;
+            sb.append("level(");
+            sb.append(i);
+            sb.append(") ");
+            formatTimeMs(sb, time/1000);
+            sb.append("(");
+            sb.append(formatRatioLocked(time, whichBatteryRealtime));
+            sb.append(") ");
+            sb.append(getWifiSignalStrengthCount(i, which));
             sb.append("x");
         }
         if (!didOne) sb.append(" (no activity)");
@@ -3039,6 +3193,16 @@
         long lastTime = -1;
         long firstTime = -1;
 
+        void reset() {
+            oldState = oldState2 = 0;
+            oldLevel = -1;
+            oldStatus = -1;
+            oldHealth = -1;
+            oldPlug = -1;
+            oldTemp = -1;
+            oldVolt = -1;
+        }
+
         public void printNextItem(PrintWriter pw, HistoryItem rec, long baseTime, boolean checkin,
                 boolean verbose) {
             if (!checkin) {
@@ -3062,6 +3226,7 @@
                     pw.print(":");
                 }
                 pw.println("START");
+                reset();
             } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
                     || rec.cmd == HistoryItem.CMD_RESET) {
                 if (checkin) {
@@ -3069,6 +3234,7 @@
                 }
                 if (rec.cmd == HistoryItem.CMD_RESET) {
                     pw.print("RESET:");
+                    reset();
                 }
                 pw.print("TIME:");
                 if (checkin) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 06c05ee..9b6f0ea 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2460,6 +2460,18 @@
         public static final String POINTER_SPEED = "pointer_speed";
 
         /**
+         * Whether lock-to-app will be triggered by long-press on recents.
+         * @hide
+         */
+        public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
+
+        /**
+         * Whether lock-to-app will lock the keyguard when exiting.
+         * @hide
+         */
+        public static final String LOCK_TO_APP_EXIT_LOCKED = "lock_to_app_exit_locked";
+
+        /**
          * I am the lolrus.
          * <p>
          * Nonzero values indicate that the user has a bukkit.
@@ -4537,12 +4549,6 @@
         public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
 
         /**
-         * Specifies the package name currently configured to be the primary phone application
-         * @hide
-         */
-        public static final String PHONE_DEFAULT_APPLICATION = "phone_default_application";
-
-        /**
          * Name of a package that the current user has explicitly allowed to see all of that
          * user's notifications.
          *
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index e936232..0017eb1 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -89,8 +89,8 @@
  * out-in behavior. Finally, note the use of the <code>targets</code> sub-tag, which
  * takes a set of {@link android.R.styleable#TransitionTarget target} tags, each
  * of which lists a specific <code>targetId</code>, <code>targetClass</code>,
- * <code>targetViewName</code>, <code>excludeId</code>, <code>excludeClass</code>, or
- * <code>excludeViewName</code>, which this transition acts upon.
+ * <code>targetName</code>, <code>excludeId</code>, <code>excludeClass</code>, or
+ * <code>excludeName</code>, which this transition acts upon.
  * Use of targets is optional, but can be used to either limit the time spent checking
  * attributes on unchanging views, or limiting the types of animations run on specific views.
  * In this case, we know that only the <code>grayscaleContainer</code> will be
@@ -115,9 +115,9 @@
 
     /**
      * With {@link #setMatchOrder(int...)}, chooses to match by
-     * {@link android.view.View#getViewName()}. Null names will not be matched.
+     * {@link android.view.View#getTransitionName()}. Null names will not be matched.
      */
-    public static final int MATCH_VIEW_NAME = 0x2;
+    public static final int MATCH_NAME = 0x2;
 
     /**
      * With {@link #setMatchOrder(int...)}, chooses to match by
@@ -135,7 +135,7 @@
     private static final int MATCH_LAST = MATCH_ITEM_ID;
 
     private static final int[] DEFAULT_MATCH_ORDER = {
-        MATCH_VIEW_NAME,
+        MATCH_NAME,
         MATCH_INSTANCE,
         MATCH_ID,
         MATCH_ITEM_ID,
@@ -207,7 +207,7 @@
     EpicenterCallback mEpicenterCallback;
 
     // For Fragment shared element transitions, linking views explicitly by mismatching
-    // viewNames.
+    // transitionNames.
     ArrayMap<String, String> mNameOverrides;
 
     /**
@@ -378,17 +378,17 @@
     /**
      * Sets the order in which Transition matches View start and end values.
      * <p>
-     * The default behavior is to match first by {@link android.view.View#getViewName()},
+     * The default behavior is to match first by {@link android.view.View#getTransitionName()},
      * then by View instance, then by {@link android.view.View#getId()} and finally
      * by its item ID if it is in a direct child of ListView. The caller can
      * choose to have only some or all of the values of {@link #MATCH_INSTANCE},
-     * {@link #MATCH_VIEW_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}. Only
+     * {@link #MATCH_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}. Only
      * the match algorithms supplied will be used to determine whether Views are the
      * the same in both the start and end Scene. Views that do not match will be considered
      * as entering or leaving the Scene.
      * </p>
      * @param matches A list of zero or more of {@link #MATCH_INSTANCE},
-     *                {@link #MATCH_VIEW_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}.
+     *                {@link #MATCH_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}.
      *                If none are provided, then the default match order will be set.
      */
     public void setMatchOrder(int... matches) {
@@ -500,9 +500,9 @@
     }
 
     /**
-     * Match start/end values by Adapter viewName. Adds matched values to startValuesList
+     * Match start/end values by Adapter transitionName. Adds matched values to startValuesList
      * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
-     * startNames and endNames as a guide for which Views have unique viewNames.
+     * startNames and endNames as a guide for which Views have unique transitionNames.
      */
     private void matchNames(ArrayList<TransitionValues> startValuesList,
             ArrayList<TransitionValues> endValuesList,
@@ -563,7 +563,7 @@
                 case MATCH_INSTANCE:
                     matchInstances(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
                     break;
-                case MATCH_VIEW_NAME:
+                case MATCH_NAME:
                     matchNames(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
                             startValues.nameValues, endValues.nameValues);
                     break;
@@ -718,8 +718,8 @@
                 }
             }
         }
-        if (mTargetNameExcludes != null && target != null && target.getViewName() != null) {
-            if (mTargetNameExcludes.contains(target.getViewName())) {
+        if (mTargetNameExcludes != null && target != null && target.getTransitionName() != null) {
+            if (mTargetNameExcludes.contains(target.getTransitionName())) {
                 return false;
             }
         }
@@ -731,7 +731,7 @@
         if (mTargetIds.contains(targetId) || mTargets.contains(target)) {
             return true;
         }
-        if (mTargetNames != null && mTargetNames.contains(target.getViewName())) {
+        if (mTargetNames != null && mTargetNames.contains(target.getTransitionName())) {
             return true;
         }
         if (mTargetTypes != null) {
@@ -882,18 +882,18 @@
     }
 
     /**
-     * Adds the viewName of a target view that this Transition is interested in
+     * Adds the transitionName of a target view that this Transition is interested in
      * animating. By default, there are no targetNames, and a Transition will
      * listen for changes on every view in the hierarchy below the sceneRoot
      * of the Scene being transitioned into. Setting targetNames constrains
-     * the Transition to only listen for, and act on, views with these viewNames.
-     * Views with different viewNames, or no viewName whatsoever, will be ignored.
+     * the Transition to only listen for, and act on, views with these transitionNames.
+     * Views with different transitionNames, or no transitionName whatsoever, will be ignored.
      *
-     * <p>Note that viewNames should be unique within the view hierarchy.</p>
+     * <p>Note that transitionNames should be unique within the view hierarchy.</p>
      *
-     * @see android.view.View#getViewName()
-     * @param targetName The viewName of a target view, must be non-null.
-     * @return The Transition to which the target viewName is added.
+     * @see android.view.View#getTransitionName()
+     * @param targetName The transitionName of a target view, must be non-null.
+     * @return The Transition to which the target transitionName is added.
      * Returning the same object makes it easier to chain calls during
      * construction, such as
      * <code>transitionSet.addTransitions(new Fade()).addTarget(someName);</code>
@@ -958,10 +958,10 @@
     }
 
     /**
-     * Removes the given targetName from the list of viewNames that this Transition
+     * Removes the given targetName from the list of transitionNames that this Transition
      * is interested in animating.
      *
-     * @param targetName The viewName of a target view, must not be null.
+     * @param targetName The transitionName of a target view, must not be null.
      * @return The Transition from which the targetName is removed.
      * Returning the same object makes it easier to chain calls during
      * construction, such as
@@ -1003,28 +1003,28 @@
     }
 
     /**
-     * Whether to add the given viewName to the list of target viewNames to exclude from this
-     * transition. The <code>exclude</code> parameter specifies whether the target
+     * Whether to add the given transitionName to the list of target transitionNames to exclude
+     * from this transition. The <code>exclude</code> parameter specifies whether the target
      * should be added to or removed from the excluded list.
      *
      * <p>Excluding targets is a general mechanism for allowing transitions to run on
      * a view hierarchy while skipping target views that should not be part of
      * the transition. For example, you may want to avoid animating children
      * of a specific ListView or Spinner. Views can be excluded by their
-     * id, their instance reference, their viewName, or by the Class of that view
+     * id, their instance reference, their transitionName, or by the Class of that view
      * (eg, {@link Spinner}).</p>
      *
      * @see #excludeTarget(View, boolean)
      * @see #excludeTarget(int, boolean)
      * @see #excludeTarget(Class, boolean)
      *
-     * @param targetViewName The name of a target to ignore when running this transition.
+     * @param targetName The name of a target to ignore when running this transition.
      * @param exclude Whether to add the target to or remove the target from the
      * current list of excluded targets.
      * @return This transition object.
      */
-    public Transition excludeTarget(String targetViewName, boolean exclude) {
-        mTargetNameExcludes = excludeObject(mTargetNameExcludes, targetViewName, exclude);
+    public Transition excludeTarget(String targetName, boolean exclude) {
+        mTargetNameExcludes = excludeObject(mTargetNameExcludes, targetName, exclude);
         return this;
     }
 
@@ -1248,7 +1248,7 @@
     /**
      * Returns the list of target IDs that this transition limits itself to
      * tracking and animating. If the list is null or empty for
-     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetNames()}, and
      * {@link #getTargetTypes()} then this transition is
      * not limited to specific views, and will handle changes to any views
      * in the hierarchy of a scene change.
@@ -1262,7 +1262,7 @@
     /**
      * Returns the list of target views that this transition limits itself to
      * tracking and animating. If the list is null or empty for
-     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetNames()}, and
      * {@link #getTargetTypes()} then this transition is
      * not limited to specific views, and will handle changes to any views
      * in the hierarchy of a scene change.
@@ -1274,23 +1274,31 @@
     }
 
     /**
-     * Returns the list of target viewNames that this transition limits itself to
+     * Returns the list of target transitionNames that this transition limits itself to
      * tracking and animating. If the list is null or empty for
-     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetNames()}, and
      * {@link #getTargetTypes()} then this transition is
      * not limited to specific views, and will handle changes to any views
      * in the hierarchy of a scene change.
      *
-     * @return the list of target viewNames
+     * @return the list of target transitionNames
+     */
+    public List<String> getTargetNames() {
+        return mTargetNames;
+    }
+
+    /**
+     * To be removed before L release.
+     * @hide
      */
     public List<String> getTargetViewNames() {
         return mTargetNames;
     }
 
     /**
-     * Returns the list of target viewNames that this transition limits itself to
+     * Returns the list of target transitionNames that this transition limits itself to
      * tracking and animating. If the list is null or empty for
-     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetNames()}, and
      * {@link #getTargetTypes()} then this transition is
      * not limited to specific views, and will handle changes to any views
      * in the hierarchy of a scene change.
@@ -1380,10 +1388,10 @@
                 transitionValuesMaps.idValues.put(id, view);
             }
         }
-        String name = view.getViewName();
+        String name = view.getTransitionName();
         if (name != null) {
             if (transitionValuesMaps.nameValues.containsKey(name)) {
-                // Duplicate viewNames: cannot match by viewName.
+                // Duplicate transitionNames: cannot match by transitionName.
                 transitionValuesMaps.nameValues.put(name, null);
             } else {
                 transitionValuesMaps.nameValues.put(name, view);
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index 5b7c737..551f78c 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -30,7 +30,6 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.StringTokenizer;
 
 /**
@@ -43,6 +42,8 @@
  */
 public class TransitionInflater {
     private static final String MATCH_INSTANCE = "instance";
+    private static final String MATCH_NAME = "name";
+    /** To be removed before L release */
     private static final String MATCH_VIEW_NAME = "viewName";
     private static final String MATCH_ID = "id";
     private static final String MATCH_ITEM_ID = "itemId";
@@ -90,8 +91,6 @@
     /**
      * Loads a {@link TransitionManager} object from a resource
      *
-     *
-     *
      * @param resource The resource id of the transition manager to load
      * @return The loaded TransitionManager object
      * @throws android.content.res.Resources.NotFoundException when the
@@ -235,20 +234,20 @@
                         com.android.internal.R.styleable.TransitionTarget);
                 int id = a.getResourceId(
                         com.android.internal.R.styleable.TransitionTarget_targetId, -1);
-                String viewName;
+                String transitionName;
                 if (id >= 0) {
                     transition.addTarget(id);
                 } else if ((id = a.getResourceId(
                         com.android.internal.R.styleable.TransitionTarget_excludeId, -1)) >= 0) {
                     transition.excludeTarget(id, true);
-                } else if ((viewName = a.getString(
-                            com.android.internal.R.styleable.TransitionTarget_targetViewName))
+                } else if ((transitionName = a.getString(
+                            com.android.internal.R.styleable.TransitionTarget_targetName))
                         != null) {
-                    transition.addTarget(viewName);
-                } else if ((viewName = a.getString(
-                        com.android.internal.R.styleable.TransitionTarget_excludeViewName))
+                    transition.addTarget(transitionName);
+                } else if ((transitionName = a.getString(
+                        com.android.internal.R.styleable.TransitionTarget_excludeName))
                         != null) {
-                    transition.excludeTarget(viewName, true);
+                    transition.excludeTarget(transitionName, true);
                 } else {
                     String className = a.getString(
                             com.android.internal.R.styleable.TransitionTarget_excludeClass);
@@ -282,8 +281,10 @@
                 matches[index] = Transition.MATCH_ID;
             } else if (MATCH_INSTANCE.equalsIgnoreCase(token)) {
                 matches[index] = Transition.MATCH_INSTANCE;
+            } else if (MATCH_NAME.equalsIgnoreCase(token)) {
+                matches[index] = Transition.MATCH_NAME;
             } else if (MATCH_VIEW_NAME.equalsIgnoreCase(token)) {
-                matches[index] = Transition.MATCH_VIEW_NAME;
+                matches[index] = Transition.MATCH_NAME;
             } else if (MATCH_ITEM_ID.equalsIgnoreCase(token)) {
                 matches[index] = Transition.MATCH_ITEM_ID;
             } else if (token.isEmpty()) {
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index c04be4f..495814a 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -244,11 +244,11 @@
     }
 
     @Override
-    public Transition excludeTarget(String targetViewName, boolean exclude) {
+    public Transition excludeTarget(String targetName, boolean exclude) {
         for (int i = 0; i < mTransitions.size(); i++) {
-            mTransitions.get(i).excludeTarget(targetViewName, exclude);
+            mTransitions.get(i).excludeTarget(targetName, exclude);
         }
-        return super.excludeTarget(targetViewName, exclude);
+        return super.excludeTarget(targetName, exclude);
     }
 
     @Override
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index f90ce51..f4a0448 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -45,6 +45,9 @@
      * @return an array of the PathDataNode.
      */
     public static PathDataNode[] createNodesFromPathData(String pathData) {
+        if (pathData == null) {
+            return null;
+        }
         int start = 0;
         int end = 1;
 
@@ -64,6 +67,57 @@
         return list.toArray(new PathDataNode[list.size()]);
     }
 
+    /**
+     * @param source The array of PathDataNode to be duplicated.
+     * @return a deep copy of the <code>source</code>.
+     */
+    public static PathDataNode[] deepCopyNodes(PathDataNode[] source) {
+        PathDataNode[] copy = new PathParser.PathDataNode[source.length];
+        for (int i = 0; i < source.length; i ++) {
+            copy[i] = new PathDataNode(source[i]);
+        }
+        return copy;
+    }
+
+    /**
+     * @param nodesFrom The source path represented in an array of PathDataNode
+     * @param nodesTo The target path represented in an array of PathDataNode
+     * @return whether the <code>nodesFrom</code> can morph into <code>nodesTo</code>
+     */
+    public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) {
+        if (nodesFrom == null || nodesTo == null) {
+            return false;
+        }
+
+        if (nodesFrom.length != nodesTo.length) {
+            return false;
+        }
+
+        for (int i = 0; i < nodesFrom.length; i ++) {
+            if (nodesFrom[i].mType != nodesTo[i].mType
+                    || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Update the target's data to match the source.
+     * Before calling this, make sure canMorph(target, source) is true.
+     *
+     * @param target The target path represented in an array of PathDataNode
+     * @param source The source path represented in an array of PathDataNode
+     */
+    public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
+        for (int i = 0; i < source.length; i ++) {
+            target[i].mType = source[i].mType;
+            for (int j = 0; j < source[i].mParams.length; j ++) {
+                target[i].mParams[j] = source[i].mParams[j];
+            }
+        }
+    }
+
     private static int nextStart(String s, int end) {
         char c;
 
@@ -132,6 +186,11 @@
         return (comma > space) ? space : comma;
     }
 
+    /**
+     * Each PathDataNode represents one command in the "d" attribute of the svg
+     * file.
+     * An array of PathDataNode can represent the whole "d" attribute.
+     */
     public static class PathDataNode {
         private char mType;
         private float[] mParams;
@@ -146,6 +205,12 @@
             mParams = Arrays.copyOf(n.mParams, n.mParams.length);
         }
 
+        /**
+         * Convert an array of PathDataNode to Path.
+         *
+         * @param node The source array of PathDataNode.
+         * @param path The target Path object.
+         */
         public static void nodesToPath(PathDataNode[] node, Path path) {
             float[] current = new float[4];
             char previousCommand = 'm';
@@ -155,6 +220,23 @@
             }
         }
 
+        /**
+         * The current PathDataNode will be interpolated between the
+         * <code>nodeFrom</code> and <code>nodeTo</code> according to the
+         * <code>fraction</code>.
+         *
+         * @param nodeFrom The start value as a PathDataNode.
+         * @param nodeTo The end value as a PathDataNode
+         * @param fraction The fraction to interpolate.
+         */
+        public void interpolatePathDataNode(PathDataNode nodeFrom,
+                PathDataNode nodeTo, float fraction) {
+            for (int i = 0; i < nodeFrom.mParams.length; i++) {
+                mParams[i] = nodeFrom.mParams[i] * (1 - fraction)
+                        + nodeTo.mParams[i] * fraction;
+            }
+        }
+
         private static void addCommand(Path path, float[] current,
                 char previousCmd, char cmd, float[] val) {
 
@@ -523,6 +605,5 @@
                 ep1y = ep2y;
             }
         }
-
     }
 }
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 9fafc48..dcd9ba9 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -234,12 +234,11 @@
     protected static native long nFinishRecording(long renderer);
 
     @Override
-    public int drawDisplayList(RenderNode displayList, Rect dirty, int flags) {
-        return nDrawDisplayList(mRenderer, displayList.getNativeDisplayList(),
-                dirty, flags);
+    public int drawRenderNode(RenderNode renderNode, Rect dirty, int flags) {
+        return nDrawRenderNode(mRenderer, renderNode.getNativeDisplayList(), dirty, flags);
     }
 
-    private static native int nDrawDisplayList(long renderer, long displayList,
+    private static native int nDrawRenderNode(long renderer, long renderNode,
             Rect dirty, int flags);
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index b8e7d8c..263ebda 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -61,16 +61,16 @@
      * Draws the specified display list onto this canvas. The display list can only
      * be drawn if {@link android.view.RenderNode#isValid()} returns true.
      *
-     * @param displayList The display list to replay.
+     * @param renderNode The RenderNode to replay.
      */
-    public void drawDisplayList(RenderNode displayList) {
-        drawDisplayList(displayList, null, RenderNode.FLAG_CLIP_CHILDREN);
+    public void drawRenderNode(RenderNode renderNode) {
+        drawRenderNode(renderNode, null, RenderNode.FLAG_CLIP_CHILDREN);
     }
 
     /**
      * Draws the specified display list onto this canvas.
      *
-     * @param displayList The display list to replay.
+     * @param renderNode The RenderNode to replay.
      * @param dirty Ignored, can be null.
      * @param flags Optional flags about drawing, see {@link RenderNode} for
      *              the possible flags.
@@ -80,7 +80,7 @@
      *
      * @hide
      */
-    public abstract int drawDisplayList(RenderNode displayList, Rect dirty, int flags);
+    public abstract int drawRenderNode(RenderNode renderNode, Rect dirty, int flags);
 
     /**
      * Draws the specified layer onto this canvas.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 166edc2..a2ff0fb 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -222,7 +222,7 @@
         try {
             canvas.save();
             callbacks.onHardwarePreDraw(canvas);
-            canvas.drawDisplayList(view.getDisplayList());
+            canvas.drawRenderNode(view.getDisplayList());
             callbacks.onHardwarePostDraw(canvas);
             canvas.restore();
         } finally {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d25ef16..517b671 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -672,7 +672,7 @@
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
  * @attr ref android.R.styleable#View_stateListAnimator
- * @attr ref android.R.styleable#View_viewName
+ * @attr ref android.R.styleable#View_transitionName
  * @attr ref android.R.styleable#View_soundEffectsEnabled
  * @attr ref android.R.styleable#View_tag
  * @attr ref android.R.styleable#View_textAlignment
@@ -3193,18 +3193,18 @@
     private boolean mHasBackgroundTint = false;
 
     /**
-     * Display list used for backgrounds.
+     * RenderNode 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
+     * of the background drawable. It is cleared on temporary detach, and reset
      * on cleanup.
      */
-    private RenderNode mBackgroundDisplayList;
+    private RenderNode mBackgroundRenderNode;
 
     private int mBackgroundResource;
     private boolean mBackgroundSizeChanged;
 
-    private String mViewName;
+    private String mTransitionName;
 
     static class ListenerInfo {
         /**
@@ -4016,8 +4016,8 @@
                 case R.styleable.View_accessibilityLiveRegion:
                     setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
                     break;
-                case R.styleable.View_viewName:
-                    setViewName(a.getString(attr));
+                case R.styleable.View_transitionName:
+                    setTransitionName(a.getString(attr));
                     break;
                 case R.styleable.View_nestedScrollingEnabled:
                     setNestedScrollingEnabled(a.getBoolean(attr, false));
@@ -13755,8 +13755,8 @@
             mRenderNode.destroyDisplayListData();
         }
 
-        if (mBackgroundDisplayList != null && mBackgroundDisplayList.isValid()) {
-            mBackgroundDisplayList.destroyDisplayListData();
+        if (mBackgroundRenderNode != null && mBackgroundRenderNode.isValid()) {
+            mBackgroundRenderNode.destroyDisplayListData();
         }
     }
 
@@ -14471,7 +14471,7 @@
             mPrivateFlags &= ~PFLAG_INVALIDATED;
         }
 
-        RenderNode displayList = null;
+        RenderNode renderNode = null;
         Bitmap cache = null;
         boolean hasDisplayList = false;
         if (caching) {
@@ -14506,12 +14506,12 @@
         }
         useDisplayListProperties &= hasDisplayList;
         if (useDisplayListProperties) {
-            displayList = getDisplayList();
-            if (!displayList.isValid()) {
+            renderNode = getDisplayList();
+            if (!renderNode.isValid()) {
                 // Uncommon, but possible. If a view is removed from the hierarchy during the call
                 // to getDisplayList(), the display list will be marked invalid and we should not
                 // try to use it again.
-                displayList = null;
+                renderNode = null;
                 hasDisplayList = false;
                 useDisplayListProperties = false;
             }
@@ -14565,7 +14565,7 @@
                 if (transformToApply != null) {
                     if (concatMatrix) {
                         if (useDisplayListProperties) {
-                            displayList.setAnimationMatrix(transformToApply.getMatrix());
+                            renderNode.setAnimationMatrix(transformToApply.getMatrix());
                         } else {
                             // Undo the scroll translation, apply the transformation matrix,
                             // then redo the scroll translate to get the correct result.
@@ -14608,7 +14608,7 @@
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
                         if (useDisplayListProperties) {
-                            displayList.setAlpha(alpha * getAlpha() * getTransitionAlpha());
+                            renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                         } else  if (layerType == LAYER_TYPE_NONE) {
                             final int scrollX = hasDisplayList ? 0 : sx;
                             final int scrollY = hasDisplayList ? 0 : sy;
@@ -14640,12 +14640,12 @@
         }
 
         if (!useDisplayListProperties && hasDisplayList) {
-            displayList = getDisplayList();
-            if (!displayList.isValid()) {
+            renderNode = getDisplayList();
+            if (!renderNode.isValid()) {
                 // Uncommon, but possible. If a view is removed from the hierarchy during the call
                 // to getDisplayList(), the display list will be marked invalid and we should not
                 // try to use it again.
-                displayList = null;
+                renderNode = null;
                 hasDisplayList = false;
             }
         }
@@ -14678,7 +14678,7 @@
                     }
                 } else {
                     mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-                    ((HardwareCanvas) canvas).drawDisplayList(displayList, null, flags);
+                    ((HardwareCanvas) canvas).drawRenderNode(renderNode, null, flags);
                 }
             }
         } else if (cache != null) {
@@ -14949,12 +14949,12 @@
         // Attempt to use a display list if requested.
         if (canvas.isHardwareAccelerated() && mAttachInfo != null
                 && mAttachInfo.mHardwareRenderer != null) {
-            mBackgroundDisplayList = getDrawableDisplayList(background, mBackgroundDisplayList);
+            mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);
 
-            final RenderNode displayList = mBackgroundDisplayList;
+            final RenderNode displayList = mBackgroundRenderNode;
             if (displayList != null && displayList.isValid()) {
                 setBackgroundDisplayListProperties(displayList);
-                ((HardwareCanvas) canvas).drawDisplayList(displayList);
+                ((HardwareCanvas) canvas).drawRenderNode(displayList);
                 return;
             }
         }
@@ -14985,30 +14985,30 @@
      * specified Drawable.
      *
      * @param drawable Drawable for which to create a display list
-     * @param displayList Existing display list, or {@code null}
+     * @param renderNode Existing RenderNode, or {@code null}
      * @return A valid display list for the specified drawable
      */
-    private RenderNode getDrawableDisplayList(Drawable drawable, RenderNode displayList) {
-        if (displayList == null) {
-            displayList = RenderNode.create(drawable.getClass().getName());
+    private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) {
+        if (renderNode == null) {
+            renderNode = RenderNode.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);
+        final HardwareCanvas canvas = renderNode.start(width, height);
         try {
             drawable.draw(canvas);
         } finally {
-            displayList.end(canvas);
+            renderNode.end(canvas);
         }
 
         // Set up drawable properties that are view-independent.
-        displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
-        displayList.setProjectBackwards(drawable.isProjected());
-        displayList.setProjectionReceiver(true);
-        displayList.setClipToBounds(false);
-        return displayList;
+        renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        renderNode.setProjectBackwards(drawable.isProjected());
+        renderNode.setProjectionReceiver(true);
+        renderNode.setClipToBounds(false);
+        return renderNode;
     }
 
     /**
@@ -18916,15 +18916,15 @@
     }
 
     /**
-     * Adds all Views that have {@link #getViewName()} non-null to namedElements.
-     * @param namedElements Will contain all Views in the hierarchy having a view name.
+     * Adds all Views that have {@link #getTransitionName()} non-null to namedElements.
+     * @param namedElements Will contain all Views in the hierarchy having a transitionName.
      * @hide
      */
     public void findNamedViews(Map<String, View> namedElements) {
         if (getVisibility() == VISIBLE) {
-            String viewName = getViewName();
-            if (viewName != null) {
-                namedElements.put(viewName, this);
+            String transitionName = getTransitionName();
+            if (transitionName != null) {
+                namedElements.put(transitionName, this);
             }
         }
     }
@@ -19326,10 +19326,18 @@
      * Sets the name of the View to be used to identify Views in Transitions.
      * Names should be unique in the View hierarchy.
      *
-     * @param viewName The name of the View to uniquely identify it for Transitions.
+     * @param transitionName The name of the View to uniquely identify it for Transitions.
      */
-    public final void setViewName(String viewName) {
-        mViewName = viewName;
+    public final void setTransitionName(String transitionName) {
+        mTransitionName = transitionName;
+    }
+
+    /**
+     * To be removed before L release.
+     * @hide
+     */
+    public final void setViewName(String transitionName) {
+        setTransitionName(transitionName);
     }
 
     /**
@@ -19341,11 +19349,17 @@
      * @return The name used of the View to be used to identify Views in Transitions or null
      * if no name has been given.
      */
-    public String getViewName() {
-        return mViewName;
+    public String getTransitionName() {
+        return mTransitionName;
     }
 
     /**
+     * To be removed before L release.
+     * @hide
+     */
+    public String getViewName() { return getTransitionName(); }
+
+    /**
      * 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 1e72625..45ac073 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2326,13 +2326,13 @@
      * 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 or if {@link #getViewName()} is not null.
+     * is not null or if {@link #getTransitionName()} is not null.
      */
     public boolean isTransitionGroup() {
         if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
             return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
         } else {
-            return getBackground() != null || getViewName() != null;
+            return getBackground() != null || getTransitionName() != null;
         }
     }
 
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index af1de78..3f72b4c 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -52,7 +52,7 @@
      * The View whose properties are being animated by this class. This is set at
      * construction time.
      */
-    private final View mView;
+    final View mView;
 
     /**
      * The duration of the underlying Animator object. By default, we don't set the duration
@@ -253,10 +253,9 @@
     ViewPropertyAnimator(View view) {
         mView = view;
         view.ensureTransformationInfo();
-        // TODO: Disabled because of b/15287046
-        //if (view.getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.L) {
-        //    mRTBackend = new ViewPropertyAnimatorRT(view);
-        //}
+        if (view.getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.L) {
+            mRTBackend = new ViewPropertyAnimatorRT(view);
+        }
     }
 
     /**
@@ -434,6 +433,9 @@
         }
         mPendingAnimations.clear();
         mView.removeCallbacks(mAnimationStarter);
+        if (mRTBackend != null) {
+            mRTBackend.cancelAll();
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewPropertyAnimatorRT.java b/core/java/android/view/ViewPropertyAnimatorRT.java
index 709efdb..8b4277a 100644
--- a/core/java/android/view/ViewPropertyAnimatorRT.java
+++ b/core/java/android/view/ViewPropertyAnimatorRT.java
@@ -50,6 +50,15 @@
         return true;
     }
 
+    public void cancelAll() {
+        for (int i = 0; i < mAnimators.length; i++) {
+            if (mAnimators[i] != null) {
+                mAnimators[i].cancel();
+                mAnimators[i] = null;
+            }
+        }
+    }
+
     private void doStartAnimation(ViewPropertyAnimator parent) {
         int size = parent.mPendingAnimations.size();
 
@@ -63,12 +72,22 @@
             NameValuesHolder holder = parent.mPendingAnimations.get(i);
             int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant);
 
-            RenderNodeAnimator animator = new RenderNodeAnimator(property, holder.mFromValue + holder.mDeltaValue);
+            final float finalValue = holder.mFromValue + holder.mDeltaValue;
+            RenderNodeAnimator animator = new RenderNodeAnimator(property, finalValue);
             animator.setStartDelay(startDelay);
             animator.setDuration(duration);
             animator.setInterpolator(interpolator);
             animator.setTarget(mView);
             animator.start();
+
+            // Alpha is a special snowflake that has the canonical value stored
+            // in mTransformationInfo instead of in RenderNode, so we need to update
+            // it with the final value here.
+            if (property == RenderNodeAnimator.ALPHA) {
+                // Don't need null check because ViewPropertyAnimator's
+                // ctor calls ensureTransformationInfo()
+                parent.mView.mTransformationInfo.mAlpha = finalValue;
+            }
         }
 
         parent.mPendingAnimations.clear();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 82e5ddd..f574042 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -41,6 +41,7 @@
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.media.AudioManager;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
@@ -119,6 +120,9 @@
     private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
     private static final String PROPERTY_MEDIA_DISABLED = "config.disable_media";
 
+    // property used by emulator to determine display shape
+    private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
+
     /**
      * Maximum time we allow the user to roll the trackball enough to generate
      * a key event, before resetting the counters.
@@ -325,6 +329,8 @@
     /** Set to true once doDie() has been called. */
     private boolean mRemoved;
 
+    private boolean mIsEmulator;
+
     /**
      * Consistency verifier for debugging purposes.
      */
@@ -1170,8 +1176,9 @@
         if ((mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0
                 && mDisplay.getDisplayId() == 0) {
             // we're fullscreen and not hosted in an ActivityView
-            isRound = mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_windowIsRound);
+            isRound = (mIsEmulator && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))
+                    || mContext.getResources().getBoolean(
+                            com.android.internal.R.bool.config_windowIsRound);
         }
         host.dispatchApplyWindowInsets(new WindowInsets(
                 mFitSystemWindowsInsets, isRound));
@@ -5426,6 +5433,9 @@
                         mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
                     }
                 }
+
+                // detect emulator
+                mIsEmulator = Build.HARDWARE.contains("goldfish");
             }
         });
     }
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index fa760b7..231bf2d 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -39,6 +39,12 @@
      * Resource belongs to audio capture device, like microphone.
      */
     public final static long RESOURCE_AUDIO_CAPTURE = 1 << 2;
+    /**
+     * Resource belongs to protected media identifier.
+     * After the user grants this resource, the origin can use EME APIs to generate the license
+     * requests.
+     */
+    public final static long RESOURCE_PROTECTED_MEDIA_ID = 1 << 3;
 
     /**
      * @return the origin of web content which attempt to access the restricted
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4467128..13a0849 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1420,7 +1420,7 @@
                     blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
                 }
 
-                ((HardwareCanvas) canvas).drawDisplayList(blockDisplayList, null,
+                ((HardwareCanvas) canvas).drawRenderNode(blockDisplayList, null,
                         0 /* no child clipping, our TextView parent enforces it */);
 
                 endOfPreviousBlock = blockEndLine;
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index cca29cf..9a8380d 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -90,6 +90,7 @@
     private boolean mSplitTrack;
     private CharSequence mTextOn;
     private CharSequence mTextOff;
+    private boolean mShowText;
 
     private int mTouchMode;
     private int mTouchSlop;
@@ -188,6 +189,7 @@
         mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
         mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
         mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
+        mShowText = a.getBoolean(com.android.internal.R.styleable.Switch_showText, true);
         mThumbTextPadding = a.getDimensionPixelSize(
                 com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
         mSwitchMinWidth = a.getDimensionPixelSize(
@@ -533,20 +535,43 @@
         requestLayout();
     }
 
+    /**
+     * Sets whether the on/off text should be displayed.
+     *
+     * @param showText {@code true} to display on/off text
+     * @hide
+     */
+    public void setShowText(boolean showText) {
+        if (mShowText != showText) {
+            mShowText = showText;
+            requestLayout();
+        }
+    }
+
+    /**
+     * @return whether the on/off text should be displayed
+     * @hide
+     */
+    public boolean getShowText() {
+        return mShowText;
+    }
+
     @Override
     public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (mOnLayout == null) {
-            mOnLayout = makeLayout(mTextOn);
-        }
+        if (mShowText) {
+            if (mOnLayout == null) {
+                mOnLayout = makeLayout(mTextOn);
+            }
 
-        if (mOffLayout == null) {
-            mOffLayout = makeLayout(mTextOff);
+            if (mOffLayout == null) {
+                mOffLayout = makeLayout(mTextOff);
+            }
         }
 
         mTrackDrawable.getPadding(mTempRect);
 
-        final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth())
-                + mThumbTextPadding * 2;
+        final int maxTextWidth = mShowText ? Math.max(mOnLayout.getWidth(), mOffLayout.getWidth())
+                + mThumbTextPadding * 2 : 0;
         mThumbWidth = Math.max(maxTextWidth, mThumbDrawable.getIntrinsicWidth());
 
         final int switchWidth = Math.max(mSwitchMinWidth,
@@ -568,9 +593,10 @@
     @Override
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
         super.onPopulateAccessibilityEvent(event);
-        Layout layout =  isChecked() ? mOnLayout : mOffLayout;
-        if (layout != null && !TextUtils.isEmpty(layout.getText())) {
-            event.getText().add(layout.getText());
+
+        final CharSequence text = isChecked() ? mTextOn : mTextOff;
+        if (text != null) {
+            event.getText().add(text);
         }
     }
 
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 0769b08..7a9137b 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -76,6 +76,8 @@
     void noteWifiRunningChanged(in WorkSource oldWs, in WorkSource newWs);
     void noteWifiStopped(in WorkSource ws);
     void noteWifiState(int wifiState, String accessPoint);
+    void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth);
+    void noteWifiRssiChanged(int newRssi);
     void noteBluetoothOn();
     void noteBluetoothOff();
     void noteBluetoothState(int bluetoothState);
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 7e11850..4995ea1d1 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -28,7 +28,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
-import android.webkit.WebViewFactory;
 
 import com.android.internal.util.GrowingArrayUtils;
 
@@ -55,6 +54,11 @@
     // that is done.
     public static long COMMIT_PERIOD = 3*60*60*1000;  // Commit current stats every 3 hours
 
+    // Minimum uptime period before committing.  If the COMMIT_PERIOD has elapsed but
+    // the total uptime has not exceeded this amount, then the commit will be held until
+    // it is reached.
+    public static long COMMIT_UPTIME_PERIOD = 60*60*1000;  // Must have at least 1 hour elapsed
+
     public static final int STATE_NOTHING = -1;
     public static final int STATE_PERSISTENT = 0;
     public static final int STATE_TOP = 1;
@@ -81,6 +85,24 @@
     public static final int PSS_USS_MAXIMUM = 6;
     public static final int PSS_COUNT = PSS_USS_MAXIMUM+1;
 
+    public static final int SYS_MEM_USAGE_SAMPLE_COUNT = 0;
+    public static final int SYS_MEM_USAGE_CACHED_MINIMUM = 1;
+    public static final int SYS_MEM_USAGE_CACHED_AVERAGE = 2;
+    public static final int SYS_MEM_USAGE_CACHED_MAXIMUM = 3;
+    public static final int SYS_MEM_USAGE_FREE_MINIMUM = 4;
+    public static final int SYS_MEM_USAGE_FREE_AVERAGE = 5;
+    public static final int SYS_MEM_USAGE_FREE_MAXIMUM = 6;
+    public static final int SYS_MEM_USAGE_ZRAM_MINIMUM = 7;
+    public static final int SYS_MEM_USAGE_ZRAM_AVERAGE = 8;
+    public static final int SYS_MEM_USAGE_ZRAM_MAXIMUM = 9;
+    public static final int SYS_MEM_USAGE_KERNEL_MINIMUM = 10;
+    public static final int SYS_MEM_USAGE_KERNEL_AVERAGE = 11;
+    public static final int SYS_MEM_USAGE_KERNEL_MAXIMUM = 12;
+    public static final int SYS_MEM_USAGE_NATIVE_MINIMUM = 13;
+    public static final int SYS_MEM_USAGE_NATIVE_AVERAGE = 14;
+    public static final int SYS_MEM_USAGE_NATIVE_MAXIMUM = 15;
+    public static final int SYS_MEM_USAGE_COUNT = SYS_MEM_USAGE_NATIVE_MAXIMUM+1;
+
     public static final int ADJ_NOTHING = -1;
     public static final int ADJ_MEM_FACTOR_NORMAL = 0;
     public static final int ADJ_MEM_FACTOR_MODERATE = 1;
@@ -174,7 +196,7 @@
     static final String CSV_SEP = "\t";
 
     // Current version of the parcel format.
-    private static final int PARCEL_VERSION = 14;
+    private static final int PARCEL_VERSION = 18;
     // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
     private static final int MAGIC = 0x50535453;
 
@@ -200,11 +222,16 @@
     public int mMemFactor = STATE_NOTHING;
     public long mStartTime;
 
+    public int[] mSysMemUsageTable = null;
+    public int mSysMemUsageTableSize = 0;
+    public final long[] mSysMemUsageArgs = new long[SYS_MEM_USAGE_COUNT];
+
     public long mTimePeriodStartClock;
     public long mTimePeriodStartRealtime;
     public long mTimePeriodEndRealtime;
+    public long mTimePeriodStartUptime;
+    public long mTimePeriodEndUptime;
     String mRuntime;
-    String mWebView;
     boolean mRunning;
 
     static final int LONGS_SIZE = 4096;
@@ -304,11 +331,77 @@
             mMemFactorDurations[i] += other.mMemFactorDurations[i];
         }
 
+        for (int i=0; i<other.mSysMemUsageTableSize; i++) {
+            int ent = other.mSysMemUsageTable[i];
+            int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+            long[] longs = other.mLongs.get((ent>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+            addSysMemUsage(state, longs, ((ent >> OFFSET_INDEX_SHIFT) & OFFSET_INDEX_MASK));
+        }
+
         if (other.mTimePeriodStartClock < mTimePeriodStartClock) {
             mTimePeriodStartClock = other.mTimePeriodStartClock;
             mTimePeriodStartClockStr = other.mTimePeriodStartClockStr;
         }
         mTimePeriodEndRealtime += other.mTimePeriodEndRealtime - other.mTimePeriodStartRealtime;
+        mTimePeriodEndUptime += other.mTimePeriodEndUptime - other.mTimePeriodStartUptime;
+    }
+
+    public void addSysMemUsage(long cachedMem, long freeMem, long zramMem, long kernelMem,
+            long nativeMem) {
+        if (mMemFactor != STATE_NOTHING) {
+            int state = mMemFactor * STATE_COUNT;
+            mSysMemUsageArgs[SYS_MEM_USAGE_SAMPLE_COUNT] = 1;
+            for (int i=0; i<3; i++) {
+                mSysMemUsageArgs[SYS_MEM_USAGE_CACHED_MINIMUM + i] = cachedMem;
+                mSysMemUsageArgs[SYS_MEM_USAGE_FREE_MINIMUM + i] = freeMem;
+                mSysMemUsageArgs[SYS_MEM_USAGE_ZRAM_MINIMUM + i] = zramMem;
+                mSysMemUsageArgs[SYS_MEM_USAGE_KERNEL_MINIMUM + i] = kernelMem;
+                mSysMemUsageArgs[SYS_MEM_USAGE_NATIVE_MINIMUM + i] = nativeMem;
+            }
+            addSysMemUsage(state, mSysMemUsageArgs, 0);
+        }
+    }
+
+    void addSysMemUsage(int state, long[] data, int dataOff) {
+        int idx = binarySearch(mSysMemUsageTable, mSysMemUsageTableSize, state);
+        int off;
+        if (idx >= 0) {
+            off = mSysMemUsageTable[idx];
+        } else {
+            mAddLongTable = mSysMemUsageTable;
+            mAddLongTableSize = mSysMemUsageTableSize;
+            off = addLongData(~idx, state, SYS_MEM_USAGE_COUNT);
+            mSysMemUsageTable = mAddLongTable;
+            mSysMemUsageTableSize = mAddLongTableSize;
+        }
+        long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+        idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
+        addSysMemUsage(longs, idx, data, dataOff);
+    }
+
+    static void addSysMemUsage(long[] dstData, int dstOff, long[] addData, int addOff) {
+        final long dstCount = dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT];
+        final long addCount = addData[addOff+SYS_MEM_USAGE_SAMPLE_COUNT];
+        if (dstCount == 0) {
+            dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = addCount;
+            for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i++) {
+                dstData[dstOff+i] = addData[addOff+i];
+            }
+        } else if (addCount > 0) {
+            dstData[dstOff+SYS_MEM_USAGE_SAMPLE_COUNT] = dstCount + addCount;
+            for (int i=SYS_MEM_USAGE_CACHED_MINIMUM; i<SYS_MEM_USAGE_COUNT; i+=3) {
+                if (dstData[dstOff+i] > addData[addOff+i]) {
+                    dstData[dstOff+i] = addData[addOff+i];
+                }
+                dstData[dstOff+i+1] = (long)(
+                        ((dstData[dstOff+i+1]*(double)dstCount)
+                                + (addData[addOff+i+1]*(double)addCount))
+                                / (dstCount+addCount) );
+                if (dstData[dstOff+i+2] < addData[addOff+i+2]) {
+                    dstData[dstOff+i+2] = addData[addOff+i+2];
+                }
+            }
+        }
     }
 
     public static final Parcelable.Creator<ProcessStats> CREATOR
@@ -564,6 +657,164 @@
         return totalTime;
     }
 
+    static class PssAggr {
+        long pss = 0;
+        long samples = 0;
+
+        void add(long newPss, long newSamples) {
+            pss = (long)( (pss*(double)samples) + (newPss*(double)newSamples) )
+                    / (samples+newSamples);
+            samples += newSamples;
+        }
+    }
+
+    public void computeTotalMemoryUse(TotalMemoryUseCollection data, long now) {
+        data.totalTime = 0;
+        for (int i=0; i<STATE_COUNT; i++) {
+            data.processStateWeight[i] = 0;
+            data.processStatePss[i] = 0;
+            data.processStateTime[i] = 0;
+            data.processStateSamples[i] = 0;
+        }
+        for (int i=0; i<SYS_MEM_USAGE_COUNT; i++) {
+            data.sysMemUsage[i] = 0;
+        }
+        data.sysMemCachedWeight = 0;
+        data.sysMemFreeWeight = 0;
+        data.sysMemZRamWeight = 0;
+        data.sysMemKernelWeight = 0;
+        data.sysMemNativeWeight = 0;
+        data.sysMemSamples = 0;
+        long[] totalMemUsage = new long[SYS_MEM_USAGE_COUNT];
+        for (int i=0; i<mSysMemUsageTableSize; i++) {
+            int ent = mSysMemUsageTable[i];
+            long[] longs = mLongs.get((ent>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+            int idx = (ent >> OFFSET_INDEX_SHIFT) & OFFSET_INDEX_MASK;
+            addSysMemUsage(totalMemUsage, 0, longs, idx);
+        }
+        for (int is=0; is<data.screenStates.length; is++) {
+            for (int im=0; im<data.memStates.length; im++) {
+                int memBucket = data.screenStates[is] + data.memStates[im];
+                int stateBucket = memBucket * STATE_COUNT;
+                long memTime = mMemFactorDurations[memBucket];
+                if (mMemFactor == memBucket) {
+                    memTime += now - mStartTime;
+                }
+                data.totalTime += memTime;
+                int sysIdx = binarySearch(mSysMemUsageTable, mSysMemUsageTableSize, stateBucket);
+                long[] longs = totalMemUsage;
+                int idx = 0;
+                if (sysIdx >= 0) {
+                    int ent = mSysMemUsageTable[sysIdx];
+                    long[] tmpLongs = mLongs.get((ent>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+                    int tmpIdx = (ent >> OFFSET_INDEX_SHIFT) & OFFSET_INDEX_MASK;
+                    if (tmpLongs[tmpIdx+SYS_MEM_USAGE_SAMPLE_COUNT] >= 3) {
+                        addSysMemUsage(data.sysMemUsage, 0, longs, idx);
+                        longs = tmpLongs;
+                        idx = tmpIdx;
+                    }
+                }
+                data.sysMemCachedWeight += longs[idx+SYS_MEM_USAGE_CACHED_AVERAGE]
+                        * (double)memTime;
+                data.sysMemFreeWeight += longs[idx+SYS_MEM_USAGE_FREE_AVERAGE]
+                        * (double)memTime;
+                data.sysMemZRamWeight += longs[idx+SYS_MEM_USAGE_ZRAM_AVERAGE]
+                        * (double)memTime;
+                data.sysMemKernelWeight += longs[idx+SYS_MEM_USAGE_KERNEL_AVERAGE]
+                        * (double)memTime;
+                data.sysMemNativeWeight += longs[idx+SYS_MEM_USAGE_NATIVE_AVERAGE]
+                        * (double)memTime;
+                data.sysMemSamples += longs[idx+SYS_MEM_USAGE_SAMPLE_COUNT];
+             }
+        }
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        for (int iproc=0; iproc<procMap.size(); iproc++) {
+            SparseArray<ProcessState> uids = procMap.valueAt(iproc);
+            for (int iu=0; iu<uids.size(); iu++) {
+                final ProcessState proc = uids.valueAt(iu);
+                final PssAggr fgPss = new PssAggr();
+                final PssAggr bgPss = new PssAggr();
+                final PssAggr cachedPss = new PssAggr();
+                boolean havePss = false;
+                for (int i=0; i<proc.mDurationsTableSize; i++) {
+                    int off = proc.mDurationsTable[i];
+                    int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+                    int procState = type % STATE_COUNT;
+                    long samples = proc.getPssSampleCount(type);
+                    if (samples > 0) {
+                        long avg = proc.getPssAverage(type);
+                        havePss = true;
+                        if (procState <= STATE_IMPORTANT_FOREGROUND) {
+                            fgPss.add(avg, samples);
+                        } else if (procState <= STATE_RECEIVER) {
+                            bgPss.add(avg, samples);
+                        } else {
+                            cachedPss.add(avg, samples);
+                        }
+                    }
+                }
+                if (!havePss) {
+                    continue;
+                }
+                boolean fgHasBg = false;
+                boolean fgHasCached = false;
+                boolean bgHasCached = false;
+                if (fgPss.samples < 3 && bgPss.samples > 0) {
+                    fgHasBg = true;
+                    fgPss.add(bgPss.pss, bgPss.samples);
+                }
+                if (fgPss.samples < 3 && cachedPss.samples > 0) {
+                    fgHasCached = true;
+                    fgPss.add(cachedPss.pss, cachedPss.samples);
+                }
+                if (bgPss.samples < 3 && cachedPss.samples > 0) {
+                    bgHasCached = true;
+                    bgPss.add(cachedPss.pss, cachedPss.samples);
+                }
+                if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
+                    bgPss.add(fgPss.pss, fgPss.samples);
+                }
+                if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
+                    cachedPss.add(bgPss.pss, bgPss.samples);
+                }
+                if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
+                    cachedPss.add(fgPss.pss, fgPss.samples);
+                }
+                for (int i=0; i<proc.mDurationsTableSize; i++) {
+                    final int off = proc.mDurationsTable[i];
+                    final int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+                    long time = getLong(off, 0);
+                    if (proc.mCurState == type) {
+                        time += now - proc.mStartTime;
+                    }
+                    final int procState = type % STATE_COUNT;
+                    data.processStateTime[procState] += time;
+                    long samples = proc.getPssSampleCount(type);
+                    long avg;
+                    if (samples > 0) {
+                        avg = proc.getPssAverage(type);
+                    } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
+                        samples = fgPss.samples;
+                        avg = fgPss.pss;
+                    } else if (procState <= STATE_RECEIVER) {
+                        samples = bgPss.samples;
+                        avg = bgPss.pss;
+                    } else {
+                        samples = cachedPss.samples;
+                        avg = cachedPss.pss;
+                    }
+                    double newAvg = ( (data.processStatePss[procState]
+                            * (double)data.processStateSamples[procState])
+                                + (avg*(double)samples)
+                            ) / (data.processStateSamples[procState]+samples);
+                    data.processStatePss[procState] = (long)newAvg;
+                    data.processStateSamples[procState] += samples;
+                    data.processStateWeight[procState] += avg * (double)time;
+                }
+            }
+        }
+    }
+
     static void dumpProcessState(PrintWriter pw, String prefix, ProcessState proc,
             int[] screenStates, int[] memStates, int[] procStates, long now) {
         long totalTime = 0;
@@ -679,6 +930,62 @@
         }
     }
 
+    long getSysMemUsageValue(int state, int index) {
+        int idx = binarySearch(mSysMemUsageTable, mSysMemUsageTableSize, state);
+        return idx >= 0 ? getLong(mSysMemUsageTable[idx], index) : 0;
+    }
+
+    void dumpSysMemUsageCategory(PrintWriter pw, String prefix, String label,
+            int bucket, int index) {
+        pw.print(prefix); pw.print(label);
+        pw.print(": ");
+        printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024);
+        pw.print(" min, ");
+        printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024);
+        pw.print(" avg, ");
+        printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024);
+        pw.println(" max");
+    }
+
+    void dumpSysMemUsage(PrintWriter pw, String prefix, int[] screenStates,
+            int[] memStates) {
+        int printedScreen = -1;
+        for (int is=0; is<screenStates.length; is++) {
+            int printedMem = -1;
+            for (int im=0; im<memStates.length; im++) {
+                final int iscreen = screenStates[is];
+                final int imem = memStates[im];
+                final int bucket = ((iscreen + imem) * STATE_COUNT);
+                long count = getSysMemUsageValue(bucket, SYS_MEM_USAGE_SAMPLE_COUNT);
+                if (count > 0) {
+                    pw.print(prefix);
+                    if (screenStates.length > 1) {
+                        printScreenLabel(pw, printedScreen != iscreen
+                                ? iscreen : STATE_NOTHING);
+                        printedScreen = iscreen;
+                    }
+                    if (memStates.length > 1) {
+                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, '\0');
+                        printedMem = imem;
+                    }
+                    pw.print(": ");
+                    pw.print(count);
+                    pw.println(" samples:");
+                    dumpSysMemUsageCategory(pw, prefix, "  Cached", bucket,
+                            SYS_MEM_USAGE_CACHED_MINIMUM);
+                    dumpSysMemUsageCategory(pw, prefix, "  Free", bucket,
+                            SYS_MEM_USAGE_FREE_MINIMUM);
+                    dumpSysMemUsageCategory(pw, prefix, "  ZRam", bucket,
+                            SYS_MEM_USAGE_ZRAM_MINIMUM);
+                    dumpSysMemUsageCategory(pw, prefix, "  Kernel", bucket,
+                            SYS_MEM_USAGE_KERNEL_MINIMUM);
+                    dumpSysMemUsageCategory(pw, prefix, "  Native", bucket,
+                            SYS_MEM_USAGE_NATIVE_MINIMUM);
+                }
+            }
+        }
+    }
+
     static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
             int[] memStates, int[] procStates) {
         final int NS = screenStates != null ? screenStates.length : 1;
@@ -1088,10 +1395,13 @@
         mTimePeriodStartClock = System.currentTimeMillis();
         buildTimePeriodStartClockStr();
         mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+        mTimePeriodStartUptime = mTimePeriodEndUptime = SystemClock.uptimeMillis();
         mLongs.clear();
         mLongs.add(new long[LONGS_SIZE]);
         mNextLong = 0;
         Arrays.fill(mMemFactorDurations, 0);
+        mSysMemUsageTable = null;
+        mSysMemUsageTableSize = 0;
         mStartTime = 0;
         mReadError = null;
         mFlags = 0;
@@ -1220,12 +1530,17 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        long now = SystemClock.uptimeMillis();
+        writeToParcel(out, SystemClock.uptimeMillis(), flags);
+    }
+
+    /** @hide */
+    public void writeToParcel(Parcel out, long now, int flags) {
         out.writeInt(MAGIC);
         out.writeInt(PARCEL_VERSION);
         out.writeInt(STATE_COUNT);
         out.writeInt(ADJ_COUNT);
         out.writeInt(PSS_COUNT);
+        out.writeInt(SYS_MEM_USAGE_COUNT);
         out.writeInt(LONGS_SIZE);
 
         mCommonStringToIndex = new ArrayMap<String, Integer>(mProcesses.mMap.size());
@@ -1268,8 +1583,9 @@
         out.writeLong(mTimePeriodStartClock);
         out.writeLong(mTimePeriodStartRealtime);
         out.writeLong(mTimePeriodEndRealtime);
+        out.writeLong(mTimePeriodStartUptime);
+        out.writeLong(mTimePeriodEndUptime);
         out.writeString(mRuntime);
-        out.writeString(mWebView);
         out.writeInt(mFlags);
 
         out.writeInt(mLongs.size());
@@ -1287,6 +1603,13 @@
         }
         writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
 
+        out.writeInt(mSysMemUsageTableSize);
+        for (int i=0; i<mSysMemUsageTableSize; i++) {
+            if (DEBUG_PARCEL) Slog.i(TAG, "Writing sys mem usage #" + i + ": "
+                    + printLongOffset(mSysMemUsageTable[i]));
+            out.writeInt(mSysMemUsageTable[i]);
+        }
+
         out.writeInt(NPROC);
         for (int ip=0; ip<NPROC; ip++) {
             writeCommonString(out, procMap.keyAt(ip));
@@ -1417,6 +1740,9 @@
         if (!readCheckedInt(in, PSS_COUNT, "pss count")) {
             return;
         }
+        if (!readCheckedInt(in, SYS_MEM_USAGE_COUNT, "sys mem usage count")) {
+            return;
+        }
         if (!readCheckedInt(in, LONGS_SIZE, "longs size")) {
             return;
         }
@@ -1427,8 +1753,9 @@
         buildTimePeriodStartClockStr();
         mTimePeriodStartRealtime = in.readLong();
         mTimePeriodEndRealtime = in.readLong();
+        mTimePeriodStartUptime = in.readLong();
+        mTimePeriodEndUptime = in.readLong();
         mRuntime = in.readString();
-        mWebView = in.readString();
         mFlags = in.readInt();
 
         final int NLONGS = in.readInt();
@@ -1447,6 +1774,12 @@
 
         readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
 
+        mSysMemUsageTable = readTableFromParcel(in, TAG, "sys mem usage");
+        if (mSysMemUsageTable == BAD_TABLE) {
+            return;
+        }
+        mSysMemUsageTableSize = mSysMemUsageTable != null ? mSysMemUsageTable.length : 0;
+
         int NPROC = in.readInt();
         if (NPROC < 0) {
             mReadError = "bad process count: " + NPROC;
@@ -1826,6 +2159,10 @@
             boolean dumpAll, boolean activeOnly) {
         long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
                 mStartTime, now);
+        if (mSysMemUsageTable != null) {
+            pw.println("System memory usage:");
+            dumpSysMemUsage(pw, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
+        }
         ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
         boolean printedHeader = false;
         boolean sepNeeded = false;
@@ -2089,10 +2426,57 @@
         dumpTotalsLocked(pw, now);
     }
 
+    long printMemoryCategory(PrintWriter pw, String prefix, String label, double memWeight,
+            long totalTime, long curTotalMem, int samples) {
+        if (memWeight != 0) {
+            long mem = (long)(memWeight * 1024 / totalTime);
+            pw.print(prefix);
+            pw.print(label);
+            pw.print(": ");
+            printSizeValue(pw, mem);
+            pw.print(" (");
+            pw.print(samples);
+            pw.print(" samples)");
+            pw.println();
+            return curTotalMem + mem;
+        }
+        return curTotalMem;
+    }
+
     void dumpTotalsLocked(PrintWriter pw, long now) {
         pw.println("Run time Stats:");
         dumpSingleTime(pw, "  ", mMemFactorDurations, mMemFactor, mStartTime, now);
         pw.println();
+        pw.println("Memory usage:");
+        TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
+                ALL_MEM_ADJ);
+        computeTotalMemoryUse(totalMem, now);
+        long totalPss = 0;
+        totalPss = printMemoryCategory(pw, "  ", "Kernel ", totalMem.sysMemKernelWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        totalPss = printMemoryCategory(pw, "  ", "Native ", totalMem.sysMemNativeWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        for (int i=0; i<STATE_COUNT; i++) {
+            // Skip restarting service state -- that is not actually a running process.
+            if (i != STATE_SERVICE_RESTARTING) {
+                totalPss = printMemoryCategory(pw, "  ", STATE_NAMES[i],
+                        totalMem.processStateWeight[i], totalMem.totalTime, totalPss,
+                        totalMem.processStateSamples[i]);
+            }
+        }
+        totalPss = printMemoryCategory(pw, "  ", "Cached ", totalMem.sysMemCachedWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        totalPss = printMemoryCategory(pw, "  ", "Free   ", totalMem.sysMemFreeWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        totalPss = printMemoryCategory(pw, "  ", "Z-Ram   ", totalMem.sysMemZRamWeight,
+                totalMem.totalTime, totalPss, totalMem.sysMemSamples);
+        pw.print("  TOTAL  : ");
+        printSizeValue(pw, totalPss);
+        pw.println();
+        printMemoryCategory(pw, "  ", STATE_NAMES[STATE_SERVICE_RESTARTING],
+                totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss,
+                totalMem.processStateSamples[STATE_SERVICE_RESTARTING]);
+        pw.println();
         pw.print("          Start time: ");
         pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock));
         pw.println();
@@ -2118,8 +2502,6 @@
         }
         pw.print(' ');
         pw.print(mRuntime);
-        pw.print(' ');
-        pw.print(mWebView);
         pw.println();
     }
 
@@ -2208,7 +2590,7 @@
     public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
         final long now = SystemClock.uptimeMillis();
         final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
-        pw.println("vers,4");
+        pw.println("vers,5");
         pw.print("period,"); pw.print(mTimePeriodStartClockStr);
         pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
         pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
@@ -2229,7 +2611,7 @@
             pw.print(",partial");
         }
         pw.println();
-        pw.print("config,"); pw.print(mRuntime); pw.print(','); pw.println(mWebView);
+        pw.print("config,"); pw.println(mRuntime);
         for (int ip=0; ip<pkgMap.size(); ip++) {
             final String pkgName = pkgMap.keyAt(ip);
             if (reqPackage != null && !reqPackage.equals(pkgName)) {
@@ -2362,6 +2744,53 @@
         pw.print("total");
         dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor,
                 mStartTime, now);
+        if (mSysMemUsageTable != null) {
+            pw.print("sysmemusage");
+            for (int i=0; i<mSysMemUsageTableSize; i++) {
+                int off = mSysMemUsageTable[i];
+                int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+                pw.print(",");
+                printProcStateTag(pw, type);
+                for (int j=SYS_MEM_USAGE_SAMPLE_COUNT; j<SYS_MEM_USAGE_COUNT; j++) {
+                    if (j > SYS_MEM_USAGE_CACHED_MINIMUM) {
+                        pw.print(":");
+                    }
+                    pw.print(getLong(off, j));
+                }
+            }
+        }
+        pw.println();
+        TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ,
+                ALL_MEM_ADJ);
+        computeTotalMemoryUse(totalMem, now);
+        pw.print("weights,");
+        pw.print(totalMem.totalTime);
+        pw.print(",");
+        pw.print(totalMem.sysMemCachedWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        pw.print(",");
+        pw.print(totalMem.sysMemFreeWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        pw.print(",");
+        pw.print(totalMem.sysMemZRamWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        pw.print(",");
+        pw.print(totalMem.sysMemKernelWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        pw.print(",");
+        pw.print(totalMem.sysMemNativeWeight);
+        pw.print(":");
+        pw.print(totalMem.sysMemSamples);
+        for (int i=0; i<STATE_COUNT; i++) {
+            pw.print(",");
+            pw.print(totalMem.processStateWeight[i]);
+            pw.print(":");
+            pw.print(totalMem.processStateSamples[i]);
+        }
         pw.println();
     }
 
@@ -2452,6 +2881,15 @@
         }
     }
 
+    final public static class ProcessStateHolder {
+        public final int appVersion;
+        public ProcessStats.ProcessState state;
+
+        public ProcessStateHolder(int _appVersion) {
+            appVersion = _appVersion;
+        }
+    }
+
     public static final class ProcessState extends DurationsTable {
         public ProcessState mCommonProcess;
         public final String mPackage;
@@ -2660,7 +3098,7 @@
          * @param pkgList Processes to update.
          */
         public void setState(int state, int memFactor, long now,
-                ArrayMap<String, ProcessState> pkgList) {
+                ArrayMap<String, ProcessStateHolder> pkgList) {
             if (state < 0) {
                 state = mNumStartedServices > 0
                         ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
@@ -2770,7 +3208,7 @@
         }
 
         public void addPss(long pss, long uss, boolean always,
-                ArrayMap<String, ProcessState> pkgList) {
+                ArrayMap<String, ProcessStateHolder> pkgList) {
             ensureNotDead();
             if (!always) {
                 if (mLastPssState == mCurState && SystemClock.uptimeMillis()
@@ -2845,7 +3283,7 @@
             }
         }
 
-        public void reportExcessiveWake(ArrayMap<String, ProcessState> pkgList) {
+        public void reportExcessiveWake(ArrayMap<String, ProcessStateHolder> pkgList) {
             ensureNotDead();
             mCommonProcess.mNumExcessiveWake++;
             if (!mCommonProcess.mMultiPackage) {
@@ -2857,7 +3295,7 @@
             }
         }
 
-        public void reportExcessiveCpu(ArrayMap<String, ProcessState> pkgList) {
+        public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) {
             ensureNotDead();
             mCommonProcess.mNumExcessiveCpu++;
             if (!mCommonProcess.mMultiPackage) {
@@ -2888,7 +3326,7 @@
             }
         }
 
-        public void reportCachedKill(ArrayMap<String, ProcessState> pkgList, long pss) {
+        public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
             ensureNotDead();
             mCommonProcess.addCachedKill(1, pss, pss, pss);
             if (!mCommonProcess.mMultiPackage) {
@@ -2925,8 +3363,10 @@
             return this;
         }
 
-        private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList, int index) {
-            ProcessState proc = pkgList.valueAt(index);
+        private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
+                int index) {
+            ProcessStateHolder holder = pkgList.valueAt(index);
+            ProcessState proc = holder.state;
             if (mDead && proc.mCommonProcess != proc) {
                 // Somehow we are contining to use a process state that is dead, because
                 // it was not being told it was active during the last commit.  We can recover
@@ -2959,7 +3399,7 @@
                     throw new IllegalStateException("Didn't create per-package process "
                             + proc.mName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid);
                 }
-                pkgList.setValueAt(index, proc);
+                holder.state = proc;
             }
             return proc;
         }
@@ -3351,4 +3791,27 @@
             }
         }
     }
+
+    public static class TotalMemoryUseCollection {
+        final int[] screenStates;
+        final int[] memStates;
+
+        public TotalMemoryUseCollection(int[] _screenStates, int[] _memStates) {
+            screenStates = _screenStates;
+            memStates = _memStates;
+        }
+
+        public long totalTime;
+        public long[] processStatePss = new long[STATE_COUNT];
+        public double[] processStateWeight = new double[STATE_COUNT];
+        public long[] processStateTime = new long[STATE_COUNT];
+        public int[] processStateSamples = new int[STATE_COUNT];
+        public long[] sysMemUsage = new long[SYS_MEM_USAGE_COUNT];
+        public double sysMemCachedWeight;
+        public double sysMemFreeWeight;
+        public double sysMemZRamWeight;
+        public double sysMemKernelWeight;
+        public double sysMemNativeWeight;
+        public int sysMemSamples;
+    }
 }
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index ff0ee65..b098de8 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -93,6 +93,9 @@
 
     private File mFullRestoreSetDir;
     private HashSet<String> mFullRestorePackages;
+    private FileInputStream mCurFullRestoreStream;
+    private FileOutputStream mFullRestoreSocketStream;
+    private byte[] mFullRestoreBuffer;
 
     public LocalTransport(Context context) {
         mContext = context;
@@ -104,34 +107,41 @@
         }
     }
 
+    @Override
     public String name() {
         return new ComponentName(mContext, this.getClass()).flattenToShortString();
     }
 
+    @Override
     public Intent configurationIntent() {
         // The local transport is not user-configurable
         return null;
     }
 
+    @Override
     public String currentDestinationString() {
         return TRANSPORT_DESTINATION_STRING;
     }
 
+    @Override
     public String transportDirName() {
         return TRANSPORT_DIR_NAME;
     }
 
+    @Override
     public long requestBackupTime() {
         // any time is a good time for local backup
         return 0;
     }
 
+    @Override
     public int initializeDevice() {
         if (DEBUG) Log.v(TAG, "wiping all data");
         deleteContents(mCurrentSetDir);
-        return BackupTransport.TRANSPORT_OK;
+        return TRANSPORT_OK;
     }
 
+    @Override
     public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
         if (DEBUG) {
             try {
@@ -191,7 +201,7 @@
                         entity.write(buf, 0, dataSize);
                     } catch (IOException e) {
                         Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath());
-                        return BackupTransport.TRANSPORT_ERROR;
+                        return TRANSPORT_ERROR;
                     } finally {
                         entity.close();
                     }
@@ -199,11 +209,11 @@
                     entityFile.delete();
                 }
             }
-            return BackupTransport.TRANSPORT_OK;
+            return TRANSPORT_OK;
         } catch (IOException e) {
             // oops, something went wrong.  abort the operation and return error.
             Log.v(TAG, "Exception reading backup input:", e);
-            return BackupTransport.TRANSPORT_ERROR;
+            return TRANSPORT_ERROR;
         }
     }
 
@@ -222,6 +232,7 @@
         }
     }
 
+    @Override
     public int clearBackupData(PackageInfo packageInfo) {
         if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName);
 
@@ -243,9 +254,10 @@
             packageDir.delete();
         }
 
-        return BackupTransport.TRANSPORT_OK;
+        return TRANSPORT_OK;
     }
 
+    @Override
     public int finishBackup() {
         if (DEBUG) Log.v(TAG, "finishBackup()");
         if (mSocket != null) {
@@ -259,24 +271,27 @@
                 mFullTargetPackage = null;
                 mSocket.close();
             } catch (IOException e) {
-                return BackupTransport.TRANSPORT_ERROR;
+                return TRANSPORT_ERROR;
             } finally {
                 mSocket = null;
             }
         }
-        return BackupTransport.TRANSPORT_OK;
+        return TRANSPORT_OK;
     }
 
     // ------------------------------------------------------------------------------------
     // Full backup handling
+
+    @Override
     public long requestFullBackupTime() {
         return 0;
     }
 
+    @Override
     public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
         if (mSocket != null) {
             Log.e(TAG, "Attempt to initiate full backup while one is in progress");
-            return BackupTransport.TRANSPORT_ERROR;
+            return TRANSPORT_ERROR;
         }
 
         if (DEBUG) {
@@ -291,7 +306,7 @@
             mSocketInputStream = new FileInputStream(mSocket.getFileDescriptor());
         } catch (IOException e) {
             Log.e(TAG, "Unable to process socket for full backup");
-            return BackupTransport.TRANSPORT_ERROR;
+            return TRANSPORT_ERROR;
         }
 
         mFullTargetPackage = targetPackage.packageName;
@@ -300,18 +315,19 @@
             File tarball = new File(mCurrentSetFullDir, mFullTargetPackage);
             tarstream = new FileOutputStream(tarball);
         } catch (FileNotFoundException e) {
-            return BackupTransport.TRANSPORT_ERROR;
+            return TRANSPORT_ERROR;
         }
         mFullBackupOutputStream = new BufferedOutputStream(tarstream);
         mFullBackupBuffer = new byte[4096];
 
-        return BackupTransport.TRANSPORT_OK;
+        return TRANSPORT_OK;
     }
 
+    @Override
     public int sendBackupData(int numBytes) {
         if (mFullBackupBuffer == null) {
             Log.w(TAG, "Attempted sendBackupData before performFullBackup");
-            return BackupTransport.TRANSPORT_ERROR;
+            return TRANSPORT_ERROR;
         }
 
         if (numBytes > mFullBackupBuffer.length) {
@@ -323,21 +339,23 @@
             if (nRead < 0) {
                 // Something went wrong if we expect data but saw EOD
                 Log.w(TAG, "Unexpected EOD; failing backup");
-                return BackupTransport.TRANSPORT_ERROR;
+                return TRANSPORT_ERROR;
             }
             mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
             numBytes -= nRead;
             } catch (IOException e) {
                 Log.e(TAG, "Error handling backup data for " + mFullTargetPackage);
-                return BackupTransport.TRANSPORT_ERROR;
+                return TRANSPORT_ERROR;
             }
         }
-        return BackupTransport.TRANSPORT_OK;
+        return TRANSPORT_OK;
     }
 
     // ------------------------------------------------------------------------------------
     // Restore handling
     static final long[] POSSIBLE_SETS = { 2, 3, 4, 5, 6, 7, 8, 9 }; 
+
+    @Override
     public RestoreSet[] getAvailableRestoreSets() {
         long[] existing = new long[POSSIBLE_SETS.length + 1];
         int num = 0;
@@ -358,11 +376,13 @@
         return available;
     }
 
+    @Override
     public long getCurrentRestoreSet() {
         // The current restore set always has the same token
         return CURRENT_SET_TOKEN;
     }
 
+    @Override
     public int startRestore(long token, PackageInfo[] packages) {
         if (DEBUG) Log.v(TAG, "start restore " + token);
         mRestorePackages = packages;
@@ -371,7 +391,7 @@
         mRestoreSetDir = new File(mDataDir, Long.toString(token));
         mRestoreSetIncrementalDir = new File(mRestoreSetDir, INCREMENTAL_DIR);
         mRestoreSetFullDir = new File(mRestoreSetDir, FULL_DATA_DIR);
-        return BackupTransport.TRANSPORT_OK;
+        return TRANSPORT_OK;
     }
 
     @Override
@@ -397,6 +417,7 @@
                 if (maybeFullData.length() > 0) {
                     if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_FULL_STREAM) = " + name);
                     mRestoreType = RestoreDescription.TYPE_FULL_STREAM;
+                    mCurFullRestoreStream = null;   // ensure starting from the ground state
                     found = true;
                 }
             }
@@ -410,6 +431,7 @@
         return RestoreDescription.NO_MORE_PACKAGES;
     }
 
+    @Override
     public int getRestoreData(ParcelFileDescriptor outFd) {
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
         if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
@@ -426,7 +448,7 @@
         ArrayList<DecodedFilename> blobs = contentsByKey(packageDir);
         if (blobs == null) {  // nextRestorePackage() ensures the dir exists, so this is an error
             Log.e(TAG, "No keys for package: " + packageDir);
-            return BackupTransport.TRANSPORT_ERROR;
+            return TRANSPORT_ERROR;
         }
 
         // We expect at least some data if the directory exists in the first place
@@ -447,10 +469,10 @@
                     in.close();
                 }
             }
-            return BackupTransport.TRANSPORT_OK;
+            return TRANSPORT_OK;
         } catch (IOException e) {
             Log.e(TAG, "Unable to read backup records", e);
-            return BackupTransport.TRANSPORT_ERROR;
+            return TRANSPORT_ERROR;
         }
     }
 
@@ -487,38 +509,27 @@
         return contents;
     }
 
+    @Override
     public void finishRestore() {
         if (DEBUG) Log.v(TAG, "finishRestore()");
+        if (mRestoreType == RestoreDescription.TYPE_FULL_STREAM) {
+            resetFullRestoreState();
+        }
+        mRestoreType = 0;
     }
 
     // ------------------------------------------------------------------------------------
     // Full restore handling
 
-    public int prepareFullRestore(long token, String[] targetPackages) {
-        mRestoreSetDir = new File(mDataDir, Long.toString(token));
-        mFullRestoreSetDir = new File(mRestoreSetDir, FULL_DATA_DIR);
-        mFullRestorePackages = new HashSet<String>();
-        if (mFullRestoreSetDir.exists()) {
-            List<String> pkgs = Arrays.asList(mFullRestoreSetDir.list());
-            HashSet<String> available = new HashSet<String>(pkgs);
-
-            for (int i = 0; i < targetPackages.length; i++) {
-                if (available.contains(targetPackages[i])) {
-                    mFullRestorePackages.add(targetPackages[i]);
-                }
-            }
+    private void resetFullRestoreState() {
+        try {
+        mCurFullRestoreStream.close();
+        } catch (IOException e) {
+            Log.w(TAG, "Unable to close full restore input stream");
         }
-        return BackupTransport.TRANSPORT_OK;
-    }
-
-    /**
-     * Ask the transport what package's full data will be restored next.  When all apps'
-     * data has been delivered, the transport should return {@code null} here.
-     * @return The package name of the next application whose data will be restored, or
-     *    {@code null} if all available package has been delivered.
-     */
-    public String getNextFullRestorePackage() {
-        return null;
+        mCurFullRestoreStream = null;
+        mFullRestoreSocketStream = null;
+        mFullRestoreBuffer = null;
     }
 
     /**
@@ -543,7 +554,79 @@
      *    indicating a fatal error condition that precludes further restore operations
      *    on the current dataset.
      */
+    @Override
     public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
-        return 0;
+        if (mRestoreType != RestoreDescription.TYPE_FULL_STREAM) {
+            throw new IllegalStateException("Asked for full restore data for non-stream package");
+        }
+
+        // first chunk?
+        if (mCurFullRestoreStream == null) {
+            final String name = mRestorePackages[mRestorePackage].packageName;
+            if (DEBUG) Log.i(TAG, "Starting full restore of " + name);
+            File dataset = new File(mRestoreSetFullDir, name);
+            try {
+                mCurFullRestoreStream = new FileInputStream(dataset);
+            } catch (IOException e) {
+                // If we can't open the target package's tarball, we return the single-package
+                // error code and let the caller go on to the next package.
+                Log.e(TAG, "Unable to read archive for " + name);
+                return TRANSPORT_PACKAGE_REJECTED;
+            }
+            mFullRestoreSocketStream = new FileOutputStream(socket.getFileDescriptor());
+            mFullRestoreBuffer = new byte[32*1024];
+        }
+
+        int nRead;
+        try {
+            nRead = mCurFullRestoreStream.read(mFullRestoreBuffer);
+            if (nRead < 0) {
+                // EOF: tell the caller we're done
+                nRead = NO_MORE_DATA;
+            } else if (nRead == 0) {
+                // This shouldn't happen when reading a FileInputStream; we should always
+                // get either a positive nonzero byte count or -1.  Log the situation and
+                // treat it as EOF.
+                Log.w(TAG, "read() of archive file returned 0; treating as EOF");
+                nRead = NO_MORE_DATA;
+            } else {
+                if (DEBUG) {
+                    Log.i(TAG, "   delivering restore chunk: " + nRead);
+                }
+                mFullRestoreSocketStream.write(mFullRestoreBuffer, 0, nRead);
+            }
+        } catch (IOException e) {
+            return TRANSPORT_ERROR;  // Hard error accessing the file; shouldn't happen
+        } finally {
+            // Most transports will need to explicitly close 'socket' here, but this transport
+            // is in the same process as the caller so it can leave it up to the backup manager
+            // to manage both socket fds.
+        }
+
+        return nRead;
     }
+
+    /**
+     * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
+     * data for restore, it will invoke this method to tell the transport that it should
+     * abandon the data download for the current package.  The OS will then either call
+     * {@link #nextRestorePackage()} again to move on to restoring the next package in the
+     * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
+     * operation.
+     *
+     * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
+     *    current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
+     *    transport-level failure.  If the transport reports an error here, the entire restore
+     *    operation will immediately be finished with no further attempts to restore app data.
+     */
+    @Override
+    public int abortFullRestore() {
+        if (mRestoreType != RestoreDescription.TYPE_FULL_STREAM) {
+            throw new IllegalStateException("abortFullRestore() but not currently restoring");
+        }
+        resetFullRestoreState();
+        mRestoreType = 0;
+        return TRANSPORT_OK;
+    }
+
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 240d520..02e4b3f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkStats;
+import android.net.wifi.WifiManager;
 import android.os.BadParcelableException;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
@@ -88,7 +89,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 106 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 107 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -284,6 +285,13 @@
     int mWifiState = -1;
     final StopwatchTimer[] mWifiStateTimer = new StopwatchTimer[NUM_WIFI_STATES];
 
+    int mWifiSupplState = -1;
+    final StopwatchTimer[] mWifiSupplStateTimer = new StopwatchTimer[NUM_WIFI_SUPPL_STATES];
+
+    int mWifiSignalStrengthBin = -1;
+    final StopwatchTimer[] mWifiSignalStrengthsTimer =
+            new StopwatchTimer[NUM_WIFI_SIGNAL_STRENGTH_BINS];
+
     boolean mBluetoothOn;
     StopwatchTimer mBluetoothOnTimer;
 
@@ -291,6 +299,7 @@
     final StopwatchTimer[] mBluetoothStateTimer = new StopwatchTimer[NUM_BLUETOOTH_STATES];
 
     int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+    long mMobileRadioActiveStartTime;
     StopwatchTimer mMobileRadioActiveTimer;
     StopwatchTimer mMobileRadioActivePerAppTimer;
     LongSamplingCounter mMobileRadioActiveAdjustedTime;
@@ -1425,10 +1434,6 @@
             return 0;
         }
 
-        long getLastUpdateTimeMs() {
-            return mUpdateTime;
-        }
-
         void stopRunningLocked(long elapsedRealtimeMs) {
             // Ignore attempt to stop a timer that isn't running
             if (mNesting == 0) {
@@ -2089,7 +2094,9 @@
             if (mHistoryLastWritten.batteryLevel == cur.batteryLevel &&
                     (dataSize >= MAX_MAX_HISTORY_BUFFER
                             || ((mHistoryLastWritten.states^cur.states)
-                                    & HistoryItem.MOST_INTERESTING_STATES) == 0)) {
+                                    & HistoryItem.MOST_INTERESTING_STATES) == 0
+                            || ((mHistoryLastWritten.states2^cur.states2)
+                                    & HistoryItem.MOST_INTERESTING_STATES2) == 0)) {
                 return;
             }
 
@@ -2790,11 +2797,11 @@
                     powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
                             || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
             if (active) {
-                realElapsedRealtimeMs = elapsedRealtime;
+                mMobileRadioActiveStartTime = realElapsedRealtimeMs = elapsedRealtime;
                 mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
             } else {
                 realElapsedRealtimeMs = timestampNs / (1000*1000);
-                long lastUpdateTimeMs = mMobileRadioActiveTimer.getLastUpdateTimeMs();
+                long lastUpdateTimeMs = mMobileRadioActiveStartTime;
                 if (realElapsedRealtimeMs < lastUpdateTimeMs) {
                     Slog.wtf(TAG, "Data connection inactive timestamp " + realElapsedRealtimeMs
                             + " is before start time " + lastUpdateTimeMs);
@@ -2866,7 +2873,7 @@
         }
     }
 
-    void stopAllSignalStrengthTimersLocked(int except) {
+    void stopAllPhoneSignalStrengthTimersLocked(int except) {
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             if (i == except) {
@@ -2962,13 +2969,13 @@
                 if (!mPhoneSignalStrengthsTimer[strengthBin].isRunningLocked()) {
                     mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtime);
                 }
-                mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
-                        | (strengthBin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
+                mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK)
+                        | (strengthBin << HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT);
                 if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + strengthBin + " to: "
                         + Integer.toHexString(mHistoryCur.states));
                 newHistory = true;
             } else {
-                stopAllSignalStrengthTimersLocked(-1);
+                stopAllPhoneSignalStrengthTimersLocked(-1);
             }
             mPhoneSignalStrengthBin = strengthBin;
         }
@@ -3068,7 +3075,7 @@
         if (!mWifiOn) {
             final long elapsedRealtime = SystemClock.elapsedRealtime();
             final long uptime = SystemClock.uptimeMillis();
-            mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
+            mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
@@ -3081,7 +3088,7 @@
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
         if (mWifiOn) {
-            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
+            mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
@@ -3174,7 +3181,7 @@
         if (!mGlobalWifiRunning) {
             final long elapsedRealtime = SystemClock.elapsedRealtime();
             final long uptime = SystemClock.uptimeMillis();
-            mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
+            mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
@@ -3212,7 +3219,7 @@
         if (mGlobalWifiRunning) {
             final long elapsedRealtime = SystemClock.elapsedRealtime();
             final long uptime = SystemClock.uptimeMillis();
-            mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
+            mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
@@ -3240,6 +3247,64 @@
         }
     }
 
+    public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth) {
+        if (DEBUG) Log.i(TAG, "WiFi suppl state -> " + supplState);
+        if (mWifiSupplState != supplState) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            if (mWifiSupplState >= 0) {
+                mWifiSupplStateTimer[mWifiSupplState].stopRunningLocked(elapsedRealtime);
+            }
+            mWifiSupplState = supplState;
+            mWifiSupplStateTimer[supplState].startRunningLocked(elapsedRealtime);
+            mHistoryCur.states2 =
+                    (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK)
+                    | (supplState << HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT);
+            if (DEBUG_HISTORY) Slog.v(TAG, "Wifi suppl state " + supplState + " to: "
+                    + Integer.toHexString(mHistoryCur.states2));
+            addHistoryRecordLocked(elapsedRealtime, uptime);
+        }
+    }
+
+    void stopAllWifiSignalStrengthTimersLocked(int except) {
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        for (int i = 0; i < NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            if (i == except) {
+                continue;
+            }
+            while (mWifiSignalStrengthsTimer[i].isRunningLocked()) {
+                mWifiSignalStrengthsTimer[i].stopRunningLocked(elapsedRealtime);
+            }
+        }
+    }
+
+    public void noteWifiRssiChangedLocked(int newRssi) {
+        int strengthBin = WifiManager.calculateSignalLevel(newRssi, NUM_WIFI_SIGNAL_STRENGTH_BINS);
+        if (DEBUG) Log.i(TAG, "WiFi rssi -> " + newRssi + " bin=" + strengthBin);
+        if (mWifiSignalStrengthBin != strengthBin) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            if (mWifiSignalStrengthBin >= 0) {
+                mWifiSignalStrengthsTimer[mWifiSignalStrengthBin].stopRunningLocked(
+                        elapsedRealtime);
+            }
+            if (strengthBin >= 0) {
+                if (!mWifiSignalStrengthsTimer[strengthBin].isRunningLocked()) {
+                    mWifiSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtime);
+                }
+                mHistoryCur.states2 =
+                        (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK)
+                        | (strengthBin << HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT);
+                if (DEBUG_HISTORY) Slog.v(TAG, "Wifi signal strength " + strengthBin + " to: "
+                        + Integer.toHexString(mHistoryCur.states2));
+                addHistoryRecordLocked(elapsedRealtime, uptime);
+            } else {
+                stopAllWifiSignalStrengthTimersLocked(-1);
+            }
+            mWifiSignalStrengthBin = strengthBin;
+        }
+    }
+
     public void noteBluetoothOnLocked() {
         if (!mBluetoothOn) {
             final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -3583,6 +3648,26 @@
         return mWifiStateTimer[wifiState].getCountLocked(which);
     }
 
+    @Override public long getWifiSupplStateTime(int state,
+            long elapsedRealtimeUs, int which) {
+        return mWifiSupplStateTimer[state].getTotalTimeLocked(
+                elapsedRealtimeUs, which);
+    }
+
+    @Override public int getWifiSupplStateCount(int state, int which) {
+        return mWifiSupplStateTimer[state].getCountLocked(which);
+    }
+
+    @Override public long getWifiSignalStrengthTime(int strengthBin,
+            long elapsedRealtimeUs, int which) {
+        return mWifiSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
+                elapsedRealtimeUs, which);
+    }
+
+    @Override public int getWifiSignalStrengthCount(int strengthBin, int which) {
+        return mWifiSignalStrengthsTimer[strengthBin].getCountLocked(which);
+    }
+
     @Override public long getBluetoothOnTime(long elapsedRealtimeUs, int which) {
         return mBluetoothOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
@@ -5583,6 +5668,13 @@
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mOnBatteryTimeBase);
         }
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i, null, mOnBatteryTimeBase);
+        }
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i, null,
+                    mOnBatteryTimeBase);
+        }
         mBluetoothOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i, null, mOnBatteryTimeBase);
@@ -5859,6 +5951,12 @@
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             mWifiStateTimer[i].reset(false);
         }
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            mWifiSupplStateTimer[i].reset(false);
+        }
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            mWifiSignalStrengthsTimer[i].reset(false);
+        }
         mBluetoothOnTimer.reset(false);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].reset(false);
@@ -7015,6 +7113,12 @@
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             mWifiStateTimer[i].readSummaryFromParcelLocked(in);
         }
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            mWifiSupplStateTimer[i].readSummaryFromParcelLocked(in);
+        }
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            mWifiSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
+        }
         mBluetoothOn = false;
         mBluetoothOnTimer.readSummaryFromParcelLocked(in);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
@@ -7267,6 +7371,12 @@
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             mWifiStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            mWifiSupplStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+        }
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+        }
         mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -7539,6 +7649,14 @@
             mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
                     null, mOnBatteryTimeBase, in);
         }
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            mWifiSupplStateTimer[i] = new StopwatchTimer(null, -700-i,
+                    null, mOnBatteryTimeBase, in);
+        }
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i,
+                    null, mOnBatteryTimeBase, in);
+        }
         mBluetoothOn = false;
         mBluetoothOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase, in);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
@@ -7670,6 +7788,12 @@
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             mWifiStateTimer[i].writeToParcel(out, uSecRealtime);
         }
+        for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+            mWifiSupplStateTimer[i].writeToParcel(out, uSecRealtime);
+        }
+        for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+            mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
+        }
         mBluetoothOnTimer.writeToParcel(out, uSecRealtime);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
@@ -7771,7 +7895,7 @@
             pr.println("*** Phone timer:");
             mPhoneOnTimer.logState(pr, "  ");
             for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
-                pr.println("*** Signal strength #" + i + ":");
+                pr.println("*** Phone signal strength #" + i + ":");
                 mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
             }
             pr.println("*** Signal scanning :");
@@ -7793,6 +7917,14 @@
                 pr.println("*** Wifi state #" + i + ":");
                 mWifiStateTimer[i].logState(pr, "  ");
             }
+            for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+                pr.println("*** Wifi suppl state #" + i + ":");
+                mWifiSupplStateTimer[i].logState(pr, "  ");
+            }
+            for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+                pr.println("*** Wifi signal strength #" + i + ":");
+                mWifiSignalStrengthsTimer[i].logState(pr, "  ");
+            }
             pr.println("*** Bluetooth timer:");
             mBluetoothOnTimer.logState(pr, "  ");
             for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a7a1faad..598d6c1 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -491,8 +491,8 @@
     char profile_duration[sizeof("-Xprofile-duration:") + PROPERTY_VALUE_MAX];
     char profile_interval[sizeof("-Xprofile-interval:") + PROPERTY_VALUE_MAX];
     char profile_backoff[sizeof("-Xprofile-backoff:") + PROPERTY_VALUE_MAX];
-    char profile_top_k_threshold[sizeof("-Xprofile-top-k-threshold") + PROPERTY_VALUE_MAX];
-    char profile_top_k_change_threshold[sizeof("-Xprofile-top-k-change-threshold") + PROPERTY_VALUE_MAX];
+    char profile_top_k_threshold[sizeof("-Xprofile-top-k-threshold:") + PROPERTY_VALUE_MAX];
+    char profile_top_k_change_threshold[sizeof("-Xprofile-top-k-change-threshold:") + PROPERTY_VALUE_MAX];
     char langOption[sizeof("-Duser.language=") + 3];
     char regionOption[sizeof("-Duser.region=") + 3];
     char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:") + sizeof(propBuf)];
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 9998995..c139c9d 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -258,16 +258,16 @@
 
 // can return NULL
 static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {
-    switch (src.config()) {
-        case SkBitmap::kARGB_8888_Config:
+    switch (src.colorType()) {
+        case kN32_SkColorType:
             if (src.isOpaque()) return ToColor_S32_Opaque;
             return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;
-        case SkBitmap::kARGB_4444_Config:
+        case kARGB_4444_SkColorType:
             if (src.isOpaque()) return ToColor_S4444_Opaque;
             return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;
-        case SkBitmap::kRGB_565_Config:
+        case kRGB_565_SkColorType:
             return ToColor_S565;
-        case SkBitmap::kIndex8_Config:
+        case kIndex_8_SkColorType:
             if (src.getColorTable() == NULL) {
                 return NULL;
             }
@@ -291,7 +291,7 @@
 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
                               jint offset, jint stride, jint width, jint height,
                               jint configHandle, jboolean isMutable) {
-    SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
+    SkColorType colorType = SkBitmapConfigToColorType(static_cast<SkBitmap::Config>(configHandle));
     if (NULL != jColors) {
         size_t n = env->GetArrayLength(jColors);
         if (n < SkAbs32(stride) * (size_t)height) {
@@ -301,12 +301,12 @@
     }
 
     // ARGB_4444 is a deprecated format, convert automatically to 8888
-    if (config == SkBitmap::kARGB_4444_Config) {
-        config = SkBitmap::kARGB_8888_Config;
+    if (colorType == kARGB_4444_SkColorType) {
+        colorType = kN32_SkColorType;
     }
 
     SkBitmap bitmap;
-    bitmap.setConfig(config, width, height);
+    bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType));
 
     jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
     if (NULL == buff) {
@@ -515,28 +515,29 @@
 
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
-    const bool              isMutable = p->readInt32() != 0;
-    const SkBitmap::Config  config = (SkBitmap::Config)p->readInt32();
-    const int               width = p->readInt32();
-    const int               height = p->readInt32();
-    const int               rowBytes = p->readInt32();
-    const int               density = p->readInt32();
+    const bool        isMutable = p->readInt32() != 0;
+    const SkColorType colorType = (SkColorType)p->readInt32();
+    const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
+    const int         width = p->readInt32();
+    const int         height = p->readInt32();
+    const int         rowBytes = p->readInt32();
+    const int         density = p->readInt32();
 
-    if (SkBitmap::kARGB_8888_Config != config &&
-            SkBitmap::kRGB_565_Config != config &&
-            SkBitmap::kARGB_4444_Config != config &&
-            SkBitmap::kIndex8_Config != config &&
-            SkBitmap::kA8_Config != config) {
-        SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
+    if (kN32_SkColorType != colorType &&
+            kRGB_565_SkColorType != colorType &&
+            kARGB_4444_SkColorType != colorType &&
+            kIndex_8_SkColorType != colorType &&
+            kAlpha_8_SkColorType != colorType) {
+        SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
         return NULL;
     }
 
     SkBitmap* bitmap = new SkBitmap;
 
-    bitmap->setConfig(config, width, height, rowBytes);
+    bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes);
 
     SkColorTable* ctable = NULL;
-    if (config == SkBitmap::kIndex8_Config) {
+    if (colorType == kIndex_8_SkColorType) {
         int count = p->readInt32();
         if (count > 0) {
             size_t size = count * sizeof(SkPMColor);
@@ -587,13 +588,14 @@
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
     p->writeInt32(isMutable);
-    p->writeInt32(bitmap->config());
+    p->writeInt32(bitmap->colorType());
+    p->writeInt32(bitmap->alphaType());
     p->writeInt32(bitmap->width());
     p->writeInt32(bitmap->height());
     p->writeInt32(bitmap->rowBytes());
     p->writeInt32(density);
 
-    if (bitmap->config() == SkBitmap::kIndex8_Config) {
+    if (bitmap->colorType() == kIndex_8_SkColorType) {
         SkColorTable* ctable = bitmap->getColorTable();
         if (ctable != NULL) {
             int count = ctable->count();
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 5106f0d..86ed677 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -386,7 +386,7 @@
         // FIXME: If the alphaType is kUnpremul and the image has alpha, the
         // colors may not be correct, since Skia does not yet support drawing
         // to/from unpremultiplied bitmaps.
-        outputBitmap->setConfig(SkImageInfo::Make(scaledWidth, scaledHeight,
+        outputBitmap->setInfo(SkImageInfo::Make(scaledWidth, scaledHeight,
                 colorType, decodingBitmap.alphaType()));
         if (!outputBitmap->allocPixels(outputAllocator, NULL)) {
             return nullObjectReturn("allocation failed for scaled bitmap");
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 935e3a0..9e09280 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -703,10 +703,11 @@
                                 jboolean hasAlpha, jlong paintHandle) {
         SkCanvas* canvas = getNativeCanvas(canvasHandle);
         SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+        SkImageInfo info = SkImageInfo::Make(width, height,
+                               hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
+                               kPremul_SkAlphaType);
         SkBitmap    bitmap;
-        bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config :
-                         SkBitmap::kRGB_565_Config, width, height);
-        if (!bitmap.allocPixels()) {
+        if (!bitmap.allocPixels(info)) {
             return;
         }
 
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 4c9feca..f8bab24 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -36,6 +36,11 @@
 
 using namespace android;
 
+enum {
+    // Keep up to date with Camera.java
+    CAMERA_HAL_API_VERSION_NORMAL_CONNECT = -2,
+};
+
 struct fields_t {
     jfieldID    context;
     jfieldID    facing;
@@ -475,8 +480,8 @@
     env->ReleaseStringChars(clientPackageName, rawClientName);
 
     sp<Camera> camera;
-    if (halVersion == ICameraService::CAMERA_HAL_API_VERSION_UNSPECIFIED) {
-        // Default path: hal version is unspecified, do normal camera open.
+    if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
+        // Default path: hal version is don't care, do normal camera connect.
         camera = Camera::connect(cameraId, clientName,
                 Camera::USE_CALLING_UID);
     } else {
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index ee4c619..849531c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -287,6 +287,8 @@
     env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz,
                               "errorCallbackFromNative","(I)V"),
                               check_AudioSystem_Command(err));
+
+    env->DeleteLocalRef(clazz);
 }
 
 static jint
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index ad36843c..b174d1b 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -57,21 +57,11 @@
     fingerprint_device_t *device;
 } gContext;
 
-// TODO: remove after driver update to use new HAL
-fingerprint_msg_type_t hackTilFpDriverUpdate(fingerprint_msg_type_t t) {
-    switch(static_cast<int>(t)) {
-        case 1: return FINGERPRINT_PROCESSED;
-        case 2: return FINGERPRINT_TEMPLATE_ENROLLING;
-        default: return t;
-    }
-}
-
 // Called by the HAL to notify us of fingerprint events
 static void hal_notify_callback(fingerprint_msg_t msg) {
     uint32_t arg1 = 0;
     uint32_t arg2 = 0;
     uint32_t arg3 = 0; // TODO
-    msg.type = hackTilFpDriverUpdate(msg.type);
     switch (msg.type) {
         case FINGERPRINT_ERROR:
             arg1 = msg.data.error;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index dc1ea06..329e371 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -388,11 +388,11 @@
 static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jintArray colors, jint offset, jint stride,
         jfloat left, jfloat top, jint width, jint height, jboolean hasAlpha, jlong paintPtr) {
+    const SkImageInfo info = SkImageInfo::Make(width, height,
+                               hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
+                               kPremul_SkAlphaType);
     SkBitmap* bitmap = new SkBitmap;
-    bitmap->setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config : SkBitmap::kRGB_565_Config,
-            width, height);
-
-    if (!bitmap->allocPixels()) {
+    if (!bitmap->allocPixels(info)) {
         delete bitmap;
         return;
     }
@@ -854,13 +854,13 @@
     return reinterpret_cast<jlong>(new DisplayListRenderer);
 }
 
-static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jlong displayListPtr,
+static jint android_view_GLES20Canvas_drawRenderNode(JNIEnv* env,
+        jobject clazz, jlong rendererPtr, jlong renderNodePtr,
         jobject dirty, jint flags) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     android::uirenderer::Rect bounds;
-    status_t status = renderer->drawDisplayList(displayList, bounds, flags);
+    status_t status = renderer->drawRenderNode(renderNode, bounds, flags);
     if (status != DrawGlInfo::kStatusDone && dirty != NULL) {
         env->CallVoidMethod(dirty, gRectClassInfo.set,
                 int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
@@ -996,12 +996,10 @@
     { "nDrawTextRun",       "(JLjava/lang/String;IIIIFFZJJ)V",
             (void*) android_view_GLES20Canvas_drawTextRun },
 
-    { "nGetClipBounds",     "(JLandroid/graphics/Rect;)Z",
-            (void*) android_view_GLES20Canvas_getClipBounds },
+    { "nGetClipBounds",     "(JLandroid/graphics/Rect;)Z", (void*) android_view_GLES20Canvas_getClipBounds },
 
-    { "nFinishRecording",        "(J)J",      (void*) android_view_GLES20Canvas_finishRecording },
-    { "nDrawDisplayList",        "(JJLandroid/graphics/Rect;I)I",
-            (void*) android_view_GLES20Canvas_drawDisplayList },
+    { "nFinishRecording",   "(J)J",      (void*) android_view_GLES20Canvas_finishRecording },
+    { "nDrawRenderNode",    "(JJLandroid/graphics/Rect;I)I", (void*) android_view_GLES20Canvas_drawRenderNode },
 
     { "nCreateDisplayListRenderer", "()J",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
 
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 0210bd9..5ebed9c 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -142,16 +142,16 @@
 // Canvas management
 // ----------------------------------------------------------------------------
 
-static inline SkBitmap::Config convertPixelFormat(int32_t format) {
+static inline SkColorType convertPixelFormat(int32_t format) {
     switch (format) {
         case PIXEL_FORMAT_RGBA_8888:
-            return SkBitmap::kARGB_8888_Config;
+            return kN32_SkColorType;
         case PIXEL_FORMAT_RGBX_8888:
-            return SkBitmap::kARGB_8888_Config;
+            return kN32_SkColorType;
         case PIXEL_FORMAT_RGB_565:
-            return SkBitmap::kRGB_565_Config;
+            return kRGB_565_SkColorType;
         default:
-            return SkBitmap::kNo_Config;
+            return kUnknown_SkColorType;
     }
 }
 
@@ -188,8 +188,10 @@
     ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
 
     SkBitmap bitmap;
-    bitmap.setConfig(convertPixelFormat(buffer->getPixelFormat()),
-            buffer->getWidth(), buffer->getHeight(), bytesCount);
+    bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
+                                     convertPixelFormat(buffer->getPixelFormat()),
+                                     kPremul_SkAlphaType),
+                   bytesCount);
 
     if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
         bitmap.setPixels(bits);
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 3d14aaf5..7018751 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -173,17 +173,17 @@
     return value;
 }
 
-static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
+static inline SkColorType convertPixelFormat(PixelFormat format) {
     /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
-        we can map to SkBitmap::kARGB_8888_Config, and optionally call
+        we can map to kN32_SkColorType, and optionally call
         bitmap.setAlphaType(kOpaque_SkAlphaType) on the resulting SkBitmap
         (as an accelerator)
     */
     switch (format) {
-    case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;
-    case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;
-    case PIXEL_FORMAT_RGB_565:      return SkBitmap::kRGB_565_Config;
-    default:                        return SkBitmap::kNo_Config;
+    case PIXEL_FORMAT_RGBX_8888:    return kN32_SkColorType;
+    case PIXEL_FORMAT_RGBA_8888:    return kN32_SkColorType;
+    case PIXEL_FORMAT_RGB_565:      return kRGB_565_SkColorType;
+    default:                        return kUnknown_SkColorType;
     }
 }
 
@@ -220,12 +220,16 @@
     // Associate a SkCanvas object to this surface
     env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format);
 
+    SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
+                                         convertPixelFormat(outBuffer.format),
+                                         kPremul_SkAlphaType);
+    if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
+        info.fAlphaType = kOpaque_SkAlphaType;
+    }
+
     SkBitmap bitmap;
     ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
-    bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr);
-    if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
-        bitmap.setAlphaType(kOpaque_SkAlphaType);
-    }
+    bitmap.setInfo(info, bpr);
     if (outBuffer.width > 0 && outBuffer.height > 0) {
         bitmap.setPixels(outBuffer.bits);
     } else {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index cfc8eb8..9783e91 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -175,7 +175,7 @@
             screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());
 
     SkBitmap* bitmap = new SkBitmap();
-    bitmap->setConfig(screenshotInfo, (size_t)rowBytes);
+    bitmap->setInfo(screenshotInfo, (size_t)rowBytes);
     if (screenshotInfo.fWidth > 0 && screenshotInfo.fHeight > 0) {
         // takes ownership of ScreenshotClient
         SkMallocPixelRef* pixels = SkMallocPixelRef::NewWithProc(screenshotInfo,
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index c1ab515..5c04a78 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -73,17 +73,28 @@
 // Native layer
 // ----------------------------------------------------------------------------
 
-static inline SkBitmap::Config convertPixelFormat(int32_t format) {
-    switch (format) {
+// FIXME: consider exporting this to share (e.g. android_view_Surface.cpp)
+static inline SkImageInfo convertPixelFormat(const ANativeWindow_Buffer& buffer) {
+    SkImageInfo info;
+    info.fWidth = buffer.width;
+    info.fHeight = buffer.height;
+    switch (buffer.format) {
         case WINDOW_FORMAT_RGBA_8888:
-            return SkBitmap::kARGB_8888_Config;
+            info.fColorType = kN32_SkColorType;
+            info.fAlphaType = kPremul_SkAlphaType;
+            break;
         case WINDOW_FORMAT_RGBX_8888:
-            return SkBitmap::kARGB_8888_Config;
+            info.fColorType = kN32_SkColorType;
+            info.fAlphaType = kOpaque_SkAlphaType;
         case WINDOW_FORMAT_RGB_565:
-            return SkBitmap::kRGB_565_Config;
+            info.fColorType = kRGB_565_SkColorType;
+            info.fAlphaType = kOpaque_SkAlphaType;
         default:
-            return SkBitmap::kNo_Config;
+            info.fColorType = kUnknown_SkColorType;
+            info.fAlphaType = kIgnore_SkAlphaType;
+            break;
     }
+    return info;
 }
 
 /**
@@ -148,11 +159,7 @@
     ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format);
 
     SkBitmap bitmap;
-    bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount);
-
-    if (buffer.format == WINDOW_FORMAT_RGBX_8888) {
-        bitmap.setAlphaType(kOpaque_SkAlphaType);
-    }
+    bitmap.setInfo(convertPixelFormat(buffer), bytesCount);
 
     if (buffer.width > 0 && buffer.height > 0) {
         bitmap.setPixels(buffer.bits);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8b5dff0..fa1a563 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2742,7 +2742,8 @@
                 android:finishOnCloseSystemDialogs="true"
                 android:excludeFromRecents="true"
                 android:multiprocess="true"
-                android:documentLaunchMode="never">
+                android:documentLaunchMode="never"
+                android:relinquishTaskIdentity="true">
             <intent-filter>
                 <action android:name="android.intent.action.CHOOSER" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/core/res/res/anim/lock_screen_behind_enter.xml b/core/res/res/anim/lock_screen_behind_enter.xml
index 7e212be..ace17ae 100644
--- a/core/res/res/anim/lock_screen_behind_enter.xml
+++ b/core/res/res/anim/lock_screen_behind_enter.xml
@@ -18,7 +18,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:detachWallpaper="true" android:shareInterpolator="false" android:startOffset="60">
+    android:detachWallpaper="true" android:shareInterpolator="false" android:startOffset="100">
     <alpha
         android:fromAlpha="0.0" android:toAlpha="1.0"
         android:fillEnabled="true" android:fillBefore="true"
diff --git a/core/res/res/drawable-hdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-hdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 0000000..4d97045
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-hdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 0000000..46fb463
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_recent.png b/core/res/res/drawable-hdpi/ic_recent.png
new file mode 100644
index 0000000..8866539
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_recent.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-mdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 0000000..163f4a0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-mdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 0000000..bbfb83c7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_recent.png b/core/res/res/drawable-mdpi/ic_recent.png
new file mode 100644
index 0000000..2b607df
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_recent.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-xhdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 0000000..21d4d53
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-xhdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 0000000..2aeb9a2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_recent.png b/core/res/res/drawable-xhdpi/ic_recent.png
new file mode 100644
index 0000000..86316db
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_recent.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-xxhdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 0000000..1b11b59
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-xxhdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 0000000..ae0d655
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_recent.png b/core/res/res/drawable-xxhdpi/ic_recent.png
new file mode 100644
index 0000000..e6bd125
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_recent.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_lock_open_wht_24dp.png b/core/res/res/drawable-xxxhdpi/ic_lock_open_wht_24dp.png
new file mode 100644
index 0000000..8774412
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_lock_open_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_lock_outline_wht_24dp.png b/core/res/res/drawable-xxxhdpi/ic_lock_outline_wht_24dp.png
new file mode 100644
index 0000000..1375acc
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_lock_outline_wht_24dp.png
Binary files differ
diff --git a/core/res/res/drawable/lock_task_notify_bg.xml b/core/res/res/drawable/lock_task_notify_bg.xml
new file mode 100644
index 0000000..3a8fab5
--- /dev/null
+++ b/core/res/res/drawable/lock_task_notify_bg.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <solid android:color="@android:color/black" />
+    <corners
+        android:radius="8dip" />
+</shape>
diff --git a/core/res/res/layout/alert_dialog_leanback.xml b/core/res/res/layout/alert_dialog_leanback.xml
index 8655aea..848015c 100644
--- a/core/res/res/layout/alert_dialog_leanback.xml
+++ b/core/res/res/layout/alert_dialog_leanback.xml
@@ -1,20 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/*
-** 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.
-*/
+     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.
 -->
 
 <LinearLayout
@@ -22,11 +20,13 @@
     android:id="@+id/parentPanel"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:background="@drawable/dialog_background_material"
+    android:translationZ="@dimen/floating_window_z"
     android:layout_marginLeft="@dimen/leanback_alert_dialog_horizontal_margin"
-    android:layout_marginRight="@dimen/leanback_alert_dialog_horizontal_margin"
     android:layout_marginTop="@dimen/leanback_alert_dialog_vertical_margin"
-    android:layout_marginBottom="@dimen/leanback_alert_dialog_vertical_margin"
-    android:orientation="vertical">
+    android:layout_marginRight="@dimen/leanback_alert_dialog_horizontal_margin"
+    android:layout_marginBottom="@dimen/leanback_alert_dialog_vertical_margin">
 
     <LinearLayout android:id="@+id/topPanel"
         android:layout_width="match_parent"
@@ -37,16 +37,17 @@
             android:layout_height="wrap_content"
             android:orientation="horizontal"
             android:gravity="center_vertical|start"
-            android:minHeight="@dimen/alert_dialog_title_height"
-            android:layout_marginStart="16dip"
-            android:layout_marginEnd="16dip">
+            android:paddingStart="16dip"
+            android:paddingEnd="16dip"
+            android:paddingTop="16dip">
             <ImageView android:id="@+id/icon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingEnd="8dip"
+                android:layout_width="32dip"
+                android:layout_height="32dip"
+                android:layout_marginEnd="8dip"
+                android:scaleType="fitCenter"
                 android:src="@null" />
-            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
-                style="?android:attr/windowTitleStyle"
+            <TextView android:id="@+id/alertTitle"
+                style="?attr/windowTitleStyle"
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:layout_width="match_parent"
@@ -67,13 +68,12 @@
             android:layout_height="wrap_content"
             android:clipToPadding="false">
             <TextView android:id="@+id/message"
-                style="?android:attr/textAppearanceMedium"
+                style="?attr/textAppearanceMedium"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:paddingStart="16dip"
                 android:paddingEnd="16dip"
-                android:paddingTop="8dip"
-                android:paddingBottom="8dip"/>
+                android:paddingTop="16dip" />
         </ScrollView>
     </LinearLayout>
 
@@ -91,41 +91,32 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:minHeight="@dimen/alert_dialog_button_bar_height"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        android:gravity="end"
+        android:padding="16dip">
         <LinearLayout
-            style="?android:attr/buttonBarStyle"
-            android:layout_width="match_parent"
+            style="?attr/buttonBarStyle"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:layoutDirection="locale"
-            android:measureWithLargestChild="true">
-            <Button android:id="@+id/button2"
-                android:layout_width="wrap_content"
-                android:layout_gravity="start"
-                android:layout_weight="1"
-                android:maxLines="2"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:layout_height="wrap_content" />
+            android:layoutDirection="locale">
             <Button android:id="@+id/button3"
+                style="?attr/buttonBarButtonStyle"
                 android:layout_width="wrap_content"
-                android:layout_gravity="center_horizontal"
-                android:layout_weight="1"
+                android:layout_height="wrap_content"
                 android:maxLines="2"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:layout_height="wrap_content" />
+                android:minHeight="@dimen/alert_dialog_button_bar_height" />
+            <Button android:id="@+id/button2"
+                style="?attr/buttonBarButtonStyle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height" />
             <Button android:id="@+id/button1"
+                style="?attr/buttonBarButtonStyle"
                 android:layout_width="wrap_content"
-                android:layout_gravity="end"
-                android:layout_weight="1"
+                android:layout_height="wrap_content"
                 android:maxLines="2"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:layout_height="wrap_content" />
+                android:minHeight="@dimen/alert_dialog_button_bar_height" />
         </LinearLayout>
      </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml b/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml
index 096b015..829d5aa 100644
--- a/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml
+++ b/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml
@@ -1,20 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/*
-** 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.
-*/
+     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.
 -->
 
 <LinearLayout
@@ -22,18 +20,20 @@
     android:id="@+id/parentPanel"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:background="@drawable/dialog_background_material"
+    android:translationZ="@dimen/floating_window_z"
     android:layout_marginLeft="@dimen/leanback_alert_dialog_horizontal_margin"
-    android:layout_marginRight="@dimen/leanback_alert_dialog_horizontal_margin"
     android:layout_marginTop="@dimen/leanback_alert_dialog_vertical_margin"
-    android:layout_marginBottom="@dimen/leanback_alert_dialog_vertical_margin"
-    android:orientation="horizontal">
+    android:layout_marginRight="@dimen/leanback_alert_dialog_horizontal_margin"
+    android:layout_marginBottom="@dimen/leanback_alert_dialog_vertical_margin">
 
-  <LinearLayout
-      android:id="@+id/leftPanel"
-      android:layout_width="0dp"
-      android:layout_weight="0.66"
-      android:layout_height="wrap_content"
-      android:orientation="vertical">
+   <LinearLayout
+       android:id="@+id/leftPanel"
+       android:layout_width="0dp"
+       android:layout_weight="1"
+       android:layout_height="wrap_content"
+       android:orientation="vertical">
 
     <LinearLayout android:id="@+id/topPanel"
         android:layout_width="match_parent"
@@ -44,16 +44,17 @@
             android:layout_height="wrap_content"
             android:orientation="horizontal"
             android:gravity="center_vertical|start"
-            android:minHeight="@dimen/alert_dialog_title_height"
-            android:layout_marginStart="16dip"
-            android:layout_marginEnd="16dip">
+            android:paddingStart="16dip"
+            android:paddingEnd="16dip"
+            android:paddingTop="16dip">
             <ImageView android:id="@+id/icon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingEnd="8dip"
+                android:layout_width="32dip"
+                android:layout_height="32dip"
+                android:layout_marginEnd="8dip"
+                android:scaleType="fitCenter"
                 android:src="@null" />
-            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
-                style="?android:attr/windowTitleStyle"
+            <TextView android:id="@+id/alertTitle"
+                style="?attr/windowTitleStyle"
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:layout_width="match_parent"
@@ -66,6 +67,7 @@
     <LinearLayout android:id="@+id/contentPanel"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_weight="1"
         android:orientation="vertical"
         android:minHeight="64dp">
         <ScrollView android:id="@+id/scrollView"
@@ -73,13 +75,13 @@
             android:layout_height="wrap_content"
             android:clipToPadding="false">
             <TextView android:id="@+id/message"
-                style="?android:attr/textAppearanceMedium"
+                style="?attr/textAppearanceMedium"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:paddingStart="16dip"
                 android:paddingEnd="16dip"
-                android:paddingTop="8dip"
-                android:paddingBottom="8dip"/>
+                android:paddingTop="16dip"
+		android:paddingBottom="16dip" />
         </ScrollView>
     </LinearLayout>
 
@@ -92,51 +94,41 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
     </FrameLayout>
-  </LinearLayout>
+    </LinearLayout>
 
     <LinearLayout android:id="@+id/buttonPanel"
-        android:layout_width="0dp"
-	android:layout_weight="0.33"
-        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+android:background="#ffffff"
+        android:layout_height="wrap_content"
+	android:layout_gravity="center_vertical"
         android:minHeight="@dimen/alert_dialog_button_bar_height"
-	android:paddingLeft="32dp"
-	android:paddingRight="32dp"
-        android:orientation="horizontal">
+        android:orientation="vertical"
+        android:gravity="end"
+        android:padding="16dip">
         <LinearLayout
-            style="?android:attr/buttonBarStyle"
-            android:layout_width="match_parent"
+            style="?attr/buttonBarStyle"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-	    android:layout_gravity="center_vertical"
-            android:orientation="vertical"
             android:layoutDirection="locale"
-            android:measureWithLargestChild="true">
-            <Button android:id="@+id/button1"
-                android:layout_width="match_parent"
-                android:gravity="center_vertical"
-                android:layout_weight="1"
-                android:maxLines="2"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:layout_height="wrap_content" />
+	    android:orientation="vertical">
             <Button android:id="@+id/button3"
+                style="?attr/buttonBarButtonStyle"
                 android:layout_width="match_parent"
-                android:gravity="center_vertical"
-                android:layout_weight="1"
+                android:layout_height="wrap_content"
                 android:maxLines="2"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:layout_height="wrap_content" />
+                android:minHeight="@dimen/alert_dialog_button_bar_height" />
             <Button android:id="@+id/button2"
+                style="?attr/buttonBarButtonStyle"
                 android:layout_width="match_parent"
-                android:gravity="center_vertical"
-                android:layout_weight="1"
+                android:layout_height="wrap_content"
                 android:maxLines="2"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:layout_height="wrap_content" />
+                android:minHeight="@dimen/alert_dialog_button_bar_height" />
+            <Button android:id="@+id/button1"
+                style="?attr/buttonBarButtonStyle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height" />
         </LinearLayout>
      </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/layout/lock_to_app_enter.xml b/core/res/res/layout/lock_to_app_enter.xml
new file mode 100644
index 0000000..c034536
--- /dev/null
+++ b/core/res/res/layout/lock_to_app_enter.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingLeft="20dp"
+    android:paddingRight="20dp"
+    android:paddingBottom="12dp"
+    android:alpha=".8"
+    android:background="@drawable/lock_task_notify_bg" >
+
+    <ImageView
+        android:id="@+id/lock_icon"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="20dp"
+        android:alpha=".8"
+        android:src="@drawable/ic_lock_outline_wht_24dp" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/lock_icon"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="2dp"
+        android:textColor="@android:color/white"
+        android:alpha=".8"
+        android:text="@string/lock_to_app_start" />
+</RelativeLayout>
diff --git a/core/res/res/layout/lock_to_app_exit.xml b/core/res/res/layout/lock_to_app_exit.xml
new file mode 100644
index 0000000..4a60c80
--- /dev/null
+++ b/core/res/res/layout/lock_to_app_exit.xml
@@ -0,0 +1,45 @@
+<?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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:paddingLeft="20dp"
+    android:paddingRight="20dp"
+    android:paddingBottom="12dp"
+    android:alpha=".8"
+    android:background="@drawable/lock_task_notify_bg" >
+
+    <ImageView
+        android:id="@+id/lock_icon"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="20dp"
+        android:alpha=".8"
+        android:src="@drawable/ic_lock_open_wht_24dp" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/lock_icon"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="2dp"
+        android:textColor="@android:color/white"
+        android:alpha=".8"
+        android:text="@string/lock_to_app_exit" />
+</RelativeLayout>
diff --git a/core/res/res/layout/progress_dialog_leanback.xml b/core/res/res/layout/progress_dialog_leanback.xml
deleted file mode 100644
index 6bcad7a..0000000
--- a/core/res/res/layout/progress_dialog_leanback.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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.
-*/
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical">
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="2dip"
-        android:background="@android:color/leanback_dark_gray" />
-    <LinearLayout android:id="@+id/body"
-        android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:baselineAligned="false"
-        android:padding="16dip">
-
-        <ProgressBar android:id="@android:id/progress"
-            style="?android:attr/progressBarStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:max="10000"
-            android:layout_marginEnd="16dip" />
-
-        <TextView android:id="@+id/message"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical" />
-    </LinearLayout>
-</LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 8bf8416..5acb588 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -34,7 +34,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentTop="true"
         style="?attr/actionBarStyle"
-        android:viewName="android:action_bar"
+        android:transitionName="android:action_bar"
         android:gravity="top">
         <com.android.internal.widget.ActionBarView
             android:id="@+id/action_bar"
diff --git a/core/res/res/layout/screen_custom_title.xml b/core/res/res/layout/screen_custom_title.xml
index c8952bf..b385bed 100644
--- a/core/res/res/layout/screen_custom_title.xml
+++ b/core/res/res/layout/screen_custom_title.xml
@@ -31,7 +31,7 @@
     <FrameLayout android:id="@android:id/title_container" 
         android:layout_width="match_parent" 
         android:layout_height="?android:attr/windowTitleSize"
-        android:viewName="android:title"
+        android:transitionName="android:title"
         style="?android:attr/windowTitleBackgroundStyle">
     </FrameLayout>
     <FrameLayout android:id="@android:id/content"
diff --git a/core/res/res/layout/screen_toolbar.xml b/core/res/res/layout/screen_toolbar.xml
index 290c7da..56815f8 100644
--- a/core/res/res/layout/screen_toolbar.xml
+++ b/core/res/res/layout/screen_toolbar.xml
@@ -34,7 +34,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentTop="true"
         style="?attr/actionBarStyle"
-        android:viewName="android:action_bar"
+        android:transitionName="android:action_bar"
         android:gravity="top">
         <Toolbar
             android:id="@+id/action_bar"
diff --git a/core/res/res/transition/explode.xml b/core/res/res/transition/explode.xml
new file mode 100644
index 0000000..fe22284
--- /dev/null
+++ b/core/res/res/transition/explode.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<explode xmlns:android="http://schemas.android.com/apk/res/android"/>
diff --git a/core/res/res/transition/slide_bottom.xml b/core/res/res/transition/slide_bottom.xml
new file mode 100644
index 0000000..46dc0d6
--- /dev/null
+++ b/core/res/res/transition/slide_bottom.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<slide xmlns:android="http://schemas.android.com/apk/res/android" android:slideEdge="bottom"/>
diff --git a/core/res/res/transition/slide_left.xml b/core/res/res/transition/slide_left.xml
new file mode 100644
index 0000000..997bd97
--- /dev/null
+++ b/core/res/res/transition/slide_left.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<slide xmlns:android="http://schemas.android.com/apk/res/android" android:slideEdge="left"/>
diff --git a/core/res/res/transition/slide_right.xml b/core/res/res/transition/slide_right.xml
new file mode 100644
index 0000000..98f8f6a
--- /dev/null
+++ b/core/res/res/transition/slide_right.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<slide xmlns:android="http://schemas.android.com/apk/res/android" android:slideEdge="right"/>
diff --git a/core/res/res/transition/slide_top.xml b/core/res/res/transition/slide_top.xml
new file mode 100644
index 0000000..07ab945
--- /dev/null
+++ b/core/res/res/transition/slide_top.xml
@@ -0,0 +1,16 @@
+<?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.
+-->
+<slide xmlns:android="http://schemas.android.com/apk/res/android" android:slideEdge="top"/>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index f92ff40..3333f1b 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -16,8 +16,13 @@
 <resources>
     <style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
     <style name="Theme.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
+    <style name="Theme.Dialog.TimePicker" parent="Theme.Leanback.Dialog.TimePicker" />
     <style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+    <style name="Theme.Holo.Dialog.TimePicker" parent="Theme.Leanback.Dialog.TimePicker" />
     <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+    <style name="Theme.Holo.Light.Dialog.TimePicker" parent="Theme.Leanback.Light.Dialog.TimePicker" />
     <style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+    <style name="Theme.Material.Dialog.TimePicker" parent="Theme.Leanback.Dialog.TimePicker" />
     <style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+    <style name="Theme.Material.Light.Dialog.TimePicker" parent="Theme.Leanback.Light.Dialog.TimePicker" />
 </resources>
diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml
index e01caa3..1938675 100644
--- a/core/res/res/values-television/themes_device_defaults.xml
+++ b/core/res/res/values-television/themes_device_defaults.xml
@@ -16,4 +16,6 @@
 <resources>
     <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
     <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+    <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Leanback.Dialog.TimePicker" />
+    <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Leanback.Light.Dialog.TimePicker" />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f74a356..a8a4d7a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2424,7 +2424,7 @@
 
         <!-- Names a View such that it can be identified for Transitions. Names should be
              unique in the View hierarchy. -->
-        <attr name="viewName" format="string" />
+        <attr name="transitionName" format="string" />
 
         <!-- Specifies that this view should permit nested scrolling within a compatible
              ancestor view. -->
@@ -4813,6 +4813,32 @@
                  mirror images so that adjacent images always seam. -->
             <enum name="mirror" value="2" />
         </attr>
+        <!-- Defines the horizontal tile mode. When the tile mode is enabled, the bitmap is repeated.
+             Gravity is ignored when the tile mode is enabled. Default value is "disabled". -->
+        <attr name="tileModeX">
+            <!-- Do not tile the bitmap. This is the default value. -->
+            <enum name="disabled" value="-1" />
+            <!-- Replicates the edge color. -->
+            <enum name="clamp" value="0" />
+            <!-- Repeats the bitmap in both direction. -->
+            <enum name="repeat" value="1" />
+            <!-- Repeats the shader's image horizontally and vertically, alternating
+                 mirror images so that adjacent images always seam. -->
+            <enum name="mirror" value="2" />
+        </attr>
+        <!-- Defines the vertical tile mode. When the tile mode is enabled, the bitmap is repeated.
+             Gravity is ignored when the tile mode is enabled. Default value is "disabled". -->
+        <attr name="tileModeY">
+            <!-- Do not tile the bitmap. This is the default value. -->
+            <enum name="disabled" value="-1" />
+            <!-- Replicates the edge color. -->
+            <enum name="clamp" value="0" />
+            <!-- Repeats the bitmap in both direction. -->
+            <enum name="repeat" value="1" />
+            <!-- Repeats the shader's image horizontally and vertically, alternating
+                 mirror images so that adjacent images always seam. -->
+            <enum name="mirror" value="2" />
+        </attr>
         <!-- Enables or disables the mipmap hint. See
             {@link android.graphics.Bitmap#setHasMipMap(boolean)} for more information.
             Default value is false. -->
@@ -4971,6 +4997,12 @@
         <attr name="height" />
         <!-- Enables or disables dithering. -->
         <attr name="dither" />
+        <!-- If set, specifies the color to apply to the drawable as a tint. By default,
+             no tint is applied. May be a color state list. -->
+        <attr name="tint" />
+        <!-- When a tint color is set, specifies its Porter-Duff blending mode. The
+             default value is src_in, which treats the drawable as an alpha mask. -->
+        <attr name="tintMode" />
     </declare-styleable>
 
     <!-- ========================== -->
@@ -4978,6 +5010,16 @@
     <!-- ========================== -->
     <eat-comment />
 
+    <!-- Drawable used to draw vector paths. -->
+    <declare-styleable name="VectorDrawable">
+        <!-- If set, specifies the color to apply to the drawable as a tint. By default,
+             no tint is applied. May be a color state list. -->
+        <attr name="tint" />
+        <!-- When a tint color is set, specifies its Porter-Duff blending mode. The
+             default value is src_in, which treats the drawable as an alpha mask. -->
+        <attr name="tintMode" />
+    </declare-styleable>
+
     <!-- Define the virtual size of the drawing surface paths will draw to. -->
     <declare-styleable name="VectorDrawableViewport">
         <!-- The width of the canvas the drawing is on. -->
@@ -5281,10 +5323,10 @@
         <attr name="interpolator" />
         <!-- The match order to use for the transition. This is a comma-separated
              list of values, containing one or more of the following:
-             id, itemId, viewName, instance. These correspond to
+             id, itemId, name, instance. These correspond to
              {@link android.transition.Transition#MATCH_ID},
              {@link android.transition.Transition#MATCH_ITEM_ID},
-             {@link android.transition.Transition#MATCH_VIEW_NAME}, and
+             {@link android.transition.Transition#MATCH_NAME}, and
              {@link android.transition.Transition#MATCH_INSTANCE}, respectively.
              This corresponds to {@link android.transition.Transition#setMatchOrder(int...)}. -->
         <attr name="matchOrder" format="string" />
@@ -5339,10 +5381,10 @@
         <attr name="targetClass" />
         <!-- The fully-qualified name of the Class to exclude from this transition. -->
         <attr name="excludeClass" format="string" />
-        <!-- The viewName of the target on which this transition will animation changes. -->
-        <attr name="targetViewName" format="string" />
-        <!-- The viewName of the target to exclude from this transition. -->
-        <attr name="excludeViewName" format="string" />
+        <!-- The transitionName of the target on which this transition will animation changes. -->
+        <attr name="targetName" format="string" />
+        <!-- The transitionName of the target to exclude from this transition. -->
+        <attr name="excludeName" format="string" />
     </declare-styleable>
 
     <!-- Use <code>set</code> as the root tag of the XML resource that
@@ -5400,6 +5442,9 @@
             <enum name="floatType" value="0" />
             <!-- valueFrom and valueTo are integers. -->
             <enum name="intType"   value="1" />
+            <!-- valueFrom and valueTo are paths defined as strings.
+                 This type is used for path morphing in AnimatedVectorDrawable. -->
+            <enum name="pathType"   value="2" />
         </attr>
     </declare-styleable>
 
@@ -6747,6 +6792,8 @@
         <attr name="switchPadding" format="dimension" />
         <!-- Whether to split the track and leave a gap for the thumb drawable. -->
         <attr name="splitTrack" />
+        <!-- Whether to draw on/off text. -->
+        <attr name="showText" format="boolean" />
     </declare-styleable>
 
     <declare-styleable name="Pointer">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 4e06d9a..fc1d0df 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -985,6 +985,14 @@
          Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} -->
     <attr name="autoRemoveFromRecents" format="boolean" />
 
+    <!-- Tasks whose root has this attribute set to true will replace baseIntent with that of the
+         next activity in the task. If the next activity also has this attribute set to true then
+         it will yield the baseIntent to any activity that it launches in the same task. This
+         continues until an activity is encountered which has this attribute set to false. False
+         is the default. This attribute set to true also permits activity's use of the
+         TaskDescription to change labels, colors and icons in the recent task list. -->
+    <attr name="relinquishTaskIdentity" format="boolean" />
+
     <!-- The <code>manifest</code> tag is the root of an
          <code>AndroidManifest.xml</code> file,
          describing the contents of an Android package (.apk) file.  One
@@ -1653,6 +1661,7 @@
         <attr name="documentLaunchMode" />
         <attr name="maxRecents" />
         <attr name="autoRemoveFromRecents" />
+        <attr name="relinquishTaskIdentity" />
     </declare-styleable>
     
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index f304514..dd316ed 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -125,9 +125,6 @@
 
     <color name="micro_text_light">#434343</color>
 
-    <color name="leanback_dark_gray">#ff333333</color>
-    <color name="leanback_light_gray">#ff888888</color>
-
     <drawable name="notification_template_icon_bg">#3333B5E5</drawable>
     <drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
 
diff --git a/core/res/res/values/colors_leanback.xml b/core/res/res/values/colors_leanback.xml
new file mode 100644
index 0000000..dc0c673
--- /dev/null
+++ b/core/res/res/values/colors_leanback.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<!-- Colors specific to Leanback themes. -->
+<resources>
+    <color name="background_leanback_dark">#ff324248</color>
+    <color name="background_leanback_light">#ffeeeeee</color>
+
+    <color name="primary_text_leanback_dark">#cceeeeee</color>
+    <color name="secondary_text_leanback_dark">#99eeeeee</color>
+
+    <color name="primary_text_leanback_light">#cc222222</color>
+    <color name="secondary_text_leanback_light">#99222222</color>
+
+</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f73c958..28e66d5 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2115,7 +2115,7 @@
   <public type="attr" name="controlY1" />
   <public type="attr" name="controlX2" />
   <public type="attr" name="controlY2" />
-  <public type="attr" name="viewName" />
+  <public type="attr" name="transitionName" />
   <public type="attr" name="transitionGroup" />
   <public type="attr" name="viewportWidth" />
   <public type="attr" name="viewportHeight" />
@@ -2168,8 +2168,8 @@
   <public type="attr" name="fromId" />
   <public type="attr" name="reversible" />
   <public type="attr" name="splitTrack" />
-  <public type="attr" name="targetViewName" />
-  <public type="attr" name="excludeViewName" />
+  <public type="attr" name="targetName" />
+  <public type="attr" name="excludeName" />
   <public type="attr" name="matchOrder" />
   <public type="attr" name="windowDrawsSystemBarBackgrounds" />
   <public type="attr" name="statusBarColor"/>
@@ -2209,6 +2209,9 @@
   <public type="attr" name="fullBackupOnly" />
   <public type="attr" name="propertyXName" />
   <public type="attr" name="propertyYName" />
+  <public type="attr" name="relinquishTaskIdentity" />
+  <public type="attr" name="tileModeX" />
+  <public type="attr" name="tileModeY" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
@@ -2460,5 +2463,26 @@
   <!-- An interpolator which accelerates fast and keeps accelerating until the end. -->
   <public type="interpolator" name="fast_out_linear_in" />
 
+  <!-- Used for Activity Transitions, this transition indicates that no Transition
+       should be used. -->
   <public type="transition" name="no_transition" id="0x010f0000"/>
+  <!-- A transition that moves and resizes a view -->
+  <public type="transition" name="move"/>
+  <!-- A transition that fades views in and out. -->
+  <public type="transition" name="fade"/>
+  <!-- A transition that moves views in or out of the scene to or from the edges when
+       a view visibility changes. -->
+  <public type="transition" name="explode"/>
+  <!-- A transition that moves views in or out of the scene to or from the bottom edge when
+       a view visibility changes. -->
+  <public type="transition" name="slide_bottom"/>
+  <!-- A transition that moves views in or out of the scene to or from the top edge when
+       a view visibility changes. -->
+  <public type="transition" name="slide_top"/>
+  <!-- A transition that moves views in or out of the scene to or from the right edge when
+       a view visibility changes. -->
+  <public type="transition" name="slide_right"/>
+  <!-- A transition that moves views in or out of the scene to or from the left edge when
+       a view visibility changes. -->
+  <public type="transition" name="slide_left"/>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c8c0d23..e017f53 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4746,4 +4746,17 @@
     <!-- DO NOT TRANSLATE -->
     <string name="day_of_week_label_typeface">sans-serif</string>
 
+    <!-- Lock-to-app dialog title. -->
+    <string name="lock_to_app_title">Use lock-to-app?</string>
+    <!-- Lock-to-app dialog description. The $ is not actually shown or translated, it is a marker of where the recents icon shows up. -->
+    <string name="lock_to_app_description">Lock-to-app locks the display in a single app.\n\nTo exit press and hold the recent apps button  $</string>
+    <!-- Lock-to-app negative response. -->
+    <string name="lock_to_app_negative">NO</string>
+    <!-- Lock-to-app positive response. -->
+    <string name="lock_to_app_positive">START</string>
+    <!-- Starting lock-to-app indication. -->
+    <string name="lock_to_app_start">Start Lock-to-app</string>
+    <!-- Exting lock-to-app indication. -->
+    <string name="lock_to_app_exit">Exit Lock-to-app</string>
+
 </resources>
diff --git a/core/res/res/values/styles_leanback.xml b/core/res/res/values/styles_leanback.xml
index a37da4e..72d0379 100644
--- a/core/res/res/values/styles_leanback.xml
+++ b/core/res/res/values/styles_leanback.xml
@@ -14,46 +14,12 @@
      limitations under the License.
 -->
 <resources>
-    <style name="DialogWindowTitle.Leanback" parent="DialogWindowTitle.Holo">
-        <item name="android:textAppearance">@style/TextAppearance.Leanback.DialogWindowTitle</item>
-    </style>
-
-    <style name="TextAppearance.Leanback.DialogWindowTitle" parent="TextAppearance.Holo.DialogWindowTitle">
-        <item name="android:fontFamily">sans-serif-condensed</item>
-        <item name="android:textColor">?attr/textColorPrimary</item>
-    </style>
-
-    <style name="Leanback.ButtonBar" parent="Holo.ButtonBar">
-        <item name="showDividers">none</item>
-    </style>
-
-    <style name="AlertDialog.Leanback" parent="AlertDialog.Holo">
+    <style name="AlertDialog.Leanback" parent="AlertDialog.Material">
         <item name="layout">@android:layout/alert_dialog_leanback</item>
         <item name="buttonPanelSideLayout">@android:layout/alert_dialog_leanback_button_panel_right</item>
-        <item name="progressLayout">@android:layout/progress_dialog_leanback</item>
-        <item name="fullDark">@android:color/background_dark</item>
-        <item name="topDark">@android:color/background_dark</item>
-        <item name="centerDark">@android:color/background_dark</item>
-        <item name="bottomDark">@android:color/background_dark</item>
-        <item name="fullBright">@android:color/background_dark</item>
-        <item name="topBright">@android:color/background_dark</item>
-        <item name="centerBright">@android:color/background_dark</item>
-        <item name="bottomBright">@android:color/background_dark</item>
-        <item name="bottomMedium">@android:color/background_dark</item>
-        <item name="centerMedium">@android:color/background_dark</item>
     </style>
 
     <style name="AlertDialog.Leanback.Light">
-        <item name="fullDark">@android:color/leanback_light_gray</item>
-        <item name="topDark">@android:color/leanback_light_gray</item>
-        <item name="centerDark">@android:color/leanback_light_gray</item>
-        <item name="bottomDark">@android:color/leanback_light_gray</item>
-        <item name="fullBright">@android:color/leanback_light_gray</item>
-        <item name="topBright">@android:color/leanback_light_gray</item>
-        <item name="centerBright">@android:color/leanback_light_gray</item>
-        <item name="bottomBright">@android:color/leanback_light_gray</item>
-        <item name="bottomMedium">@android:color/leanback_light_gray</item>
-        <item name="centerMedium">@android:color/leanback_light_gray</item>
     </style>
 
 </resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 25307b9..75f905c 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -493,11 +493,12 @@
         <item name="thumb">@drawable/switch_thumb_material_anim</item>
         <item name="splitTrack">true</item>
         <item name="switchTextAppearance">@style/TextAppearance.Material.Widget.Switch</item>
-        <item name="textOn"></item>
-        <item name="textOff"></item>
+        <item name="textOn">@string/capital_on</item>
+        <item name="textOff">@string/capital_off</item>
         <item name="switchMinWidth">4dip</item>
         <item name="switchPadding">4dip</item>
         <item name="background">?attr/selectableItemBackgroundBorderless</item>
+        <item name="showText">false</item>
     </style>
 
     <style name="Widget.Material.EditText" parent="Widget.EditText"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7a871cc..3e82d08 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -604,6 +604,14 @@
   <java-symbol type="string" name="kilobyteShort" />
   <java-symbol type="string" name="last_month" />
   <java-symbol type="string" name="launchBrowserDefault" />
+  <java-symbol type="string" name="lock_to_app_title" />
+  <java-symbol type="string" name="lock_to_app_description" />
+  <java-symbol type="string" name="lock_to_app_negative" />
+  <java-symbol type="string" name="lock_to_app_positive" />
+  <java-symbol type="drawable" name="ic_recent" />
+  <java-symbol type="layout" name="lock_to_app_enter" />
+  <java-symbol type="layout" name="lock_to_app_exit" />
+  <java-symbol type="drawable" name="lock_task_notify_bg" />
   <java-symbol type="string" name="lockscreen_access_pattern_cell_added" />
   <java-symbol type="string" name="lockscreen_access_pattern_cleared" />
   <java-symbol type="string" name="lockscreen_access_pattern_detected" />
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
index eba8dec..a571b98 100644
--- a/core/res/res/values/themes_leanback.xml
+++ b/core/res/res/values/themes_leanback.xml
@@ -14,26 +14,38 @@
      limitations under the License.
 -->
 <resources>
-    <style name="Theme.Leanback.Dialog.Alert" parent="Theme.Holo.Dialog.BaseAlert">
-      <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+    <style name="Theme.Leanback.Dialog.Alert" parent="Theme.Material.Dialog.BaseAlert">
+      <item name="colorBackground">@color/background_leanback_dark</item>
+      <item name="textColorPrimary">@color/primary_text_leanback_dark</item>
+      <item name="textColorSecondary">@color/secondary_text_leanback_dark</item>
       <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
-      <item name="buttonBarStyle">@style/Leanback.ButtonBar</item>
-      <item name="listDividerAlertDialog">@null</item>
     </style>
 
-    <style name="Theme.Leanback.Light.Dialog.Alert" parent="Theme.Holo.Light.Dialog.BaseAlert">
-      <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+    <style name="Theme.Leanback.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.BaseAlert">
+      <item name="colorBackground">@color/background_leanback_light</item>
+      <item name="textColorPrimary">@color/primary_text_leanback_light</item>
+      <item name="textColorSecondary">@color/secondary_text_leanback_light</item>
       <item name="alertDialogStyle">@style/AlertDialog.Leanback.Light</item>
-      <item name="buttonBarStyle">@style/Leanback.ButtonBar</item>
-      <item name="listDividerAlertDialog">@null</item>
     </style>
 
-    <style name="Theme.Leanback.Light.Dialog" parent="Theme.Holo.Light.Dialog">
-        <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+    <style name="Theme.Leanback.Dialog.TimePicker" parent="Theme.Material.Dialog.BaseTimePicker">
+      <item name="colorBackground">@color/background_leanback_dark</item>
+      <item name="textColorPrimary">@color/primary_text_leanback_dark</item>
+      <item name="textColorSecondary">@color/secondary_text_leanback_dark</item>
+      <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
     </style>
 
-    <style name="Theme.Leanback.Dialog" parent="Theme.Holo.Dialog">
-        <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+    <style name="Theme.Leanback.Light.Dialog.TimePicker" parent="Theme.Material.Light.Dialog.BaseTimePicker">
+      <item name="colorBackground">@color/background_leanback_light</item>
+      <item name="textColorPrimary">@color/primary_text_leanback_light</item>
+      <item name="textColorSecondary">@color/secondary_text_leanback_light</item>
+      <item name="alertDialogStyle">@style/AlertDialog.Leanback.Light</item>
+    </style>
+
+    <style name="Theme.Leanback.Light.Dialog" parent="Theme.Material.Light.Dialog">
+    </style>
+
+    <style name="Theme.Leanback.Dialog" parent="Theme.Material.Dialog">
     </style>
 
     <style name="Theme.Leanback.Dialog.AppError" parent="Theme.Leanback.Dialog">
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 77e4307..b52b3a0 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1092,26 +1092,30 @@
         <item name="windowCloseOnTouchOutside">false</item>
     </style>
 
-    <!-- Material theme for alert dialog windows, which is used by the
-         {@link android.app.AlertDialog} class.  This is basically a dialog
-         but sets the background to empty so it can do two-tone backgrounds.
-         For applications targeting Honeycomb or newer, this is the default
-         AlertDialog theme. -->
-    <style name="Theme.Material.Dialog.Alert">
+    <style name="Theme.Material.Dialog.BaseAlert">
         <item name="windowBackground">@color/transparent</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
         <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
         <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
     </style>
 
-    <!-- Material theme for the TimePicker dialog windows, which is used by the
-         {@link android.app.TimePickerDialog} class. -->
-    <style name="Theme.Material.Dialog.TimePicker">
+    <!-- Material theme for alert dialog windows, which is used by the
+         {@link android.app.AlertDialog} class.  This is basically a dialog
+         but sets the background to empty so it can do two-tone backgrounds.
+         For applications targeting Honeycomb or newer, this is the default
+         AlertDialog theme. -->
+    <style name="Theme.Material.Dialog.Alert" parent="Theme.Material.Dialog.BaseAlert"/>
+
+    <style name="Theme.Material.Dialog.BaseTimePicker">
         <item name="windowBackground">@color/transparent</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
         <item name="windowContentOverlay">@null</item>
     </style>
 
+    <!-- Material theme for the TimePicker dialog windows, which is used by the
+         {@link android.app.TimePickerDialog} class. -->
+    <style name="Theme.Material.Dialog.TimePicker" parent="Theme.Material.Dialog.BaseTimePicker"/>
+
     <!-- Theme for a window that will be displayed either full-screen on
          smaller screens (small, normal) or as a dialog on larger screens
          (large, xlarge). -->
@@ -1206,25 +1210,29 @@
          (large, xlarge). -->
     <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.NoActionBar" />
 
-    <!-- Material light theme for alert dialog windows, which is used by the
-         {@link android.app.AlertDialog} class.  This is basically a dialog
-         but sets the background to empty so it can do two-tone backgrounds.
-         For applications targeting Honeycomb or newer, this is the default
-         AlertDialog theme. -->
-    <style name="Theme.Material.Light.Dialog.Alert">
+    <style name="Theme.Material.Light.Dialog.BaseAlert">
         <item name="windowBackground">@color/transparent</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
         <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
         <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
     </style>
 
-    <!-- Material Light theme for the TimePicker dialog windows, which is used by the
-         {@link android.app.TimePickerDialog} class. -->
-    <style name="Theme.Material.Light.Dialog.TimePicker">
+    <!-- Material light theme for alert dialog windows, which is used by the
+         {@link android.app.AlertDialog} class.  This is basically a dialog
+         but sets the background to empty so it can do two-tone backgrounds.
+         For applications targeting Honeycomb or newer, this is the default
+         AlertDialog theme. -->
+    <style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.BaseAlert"/>
+
+    <style name="Theme.Material.Light.Dialog.BaseTimePicker">
         <item name="windowBackground">@color/transparent</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
     </style>
 
+    <!-- Material Light theme for the TimePicker dialog windows, which is used by the
+         {@link android.app.TimePickerDialog} class. -->
+    <style name="Theme.Material.Light.Dialog.TimePicker" parent="Theme.Material.Light.Dialog.BaseTimePicker"/>
+
     <!-- Theme for a presentation window on a secondary display. -->
     <style name="Theme.Material.Light.Dialog.Presentation" parent="@style/Theme.Material.Light.NoActionBar.Fullscreen" />
 
diff --git a/docs/html/auto/images/assets/00_frame.png b/docs/html/auto/images/assets/00_frame.png
new file mode 100644
index 0000000..2a78380
--- /dev/null
+++ b/docs/html/auto/images/assets/00_frame.png
Binary files differ
diff --git a/docs/html/auto/images/assets/01_a_maps.png b/docs/html/auto/images/assets/01_a_maps.png
new file mode 100644
index 0000000..0d1b219
--- /dev/null
+++ b/docs/html/auto/images/assets/01_a_maps.png
Binary files differ
diff --git a/docs/html/auto/images/assets/01_b_now.png b/docs/html/auto/images/assets/01_b_now.png
new file mode 100644
index 0000000..043ec74
--- /dev/null
+++ b/docs/html/auto/images/assets/01_b_now.png
Binary files differ
diff --git a/docs/html/auto/images/assets/02_a_notif.gif b/docs/html/auto/images/assets/02_a_notif.gif
new file mode 100644
index 0000000..6a830ae
--- /dev/null
+++ b/docs/html/auto/images/assets/02_a_notif.gif
Binary files differ
diff --git a/docs/html/auto/images/assets/02_b_switcher.gif b/docs/html/auto/images/assets/02_b_switcher.gif
new file mode 100644
index 0000000..626f94b
--- /dev/null
+++ b/docs/html/auto/images/assets/02_b_switcher.gif
Binary files differ
diff --git a/docs/html/auto/images/assets/03_a_musict.png b/docs/html/auto/images/assets/03_a_musict.png
new file mode 100644
index 0000000..4e11243
--- /dev/null
+++ b/docs/html/auto/images/assets/03_a_musict.png
Binary files differ
diff --git a/docs/html/auto/images/assets/03_b_voice.gif b/docs/html/auto/images/assets/03_b_voice.gif
new file mode 100644
index 0000000..ddd13e4
--- /dev/null
+++ b/docs/html/auto/images/assets/03_b_voice.gif
Binary files differ
diff --git a/docs/html/auto/images/assets/do_01_switcher.png b/docs/html/auto/images/assets/do_01_switcher.png
new file mode 100644
index 0000000..b654a13
--- /dev/null
+++ b/docs/html/auto/images/assets/do_01_switcher.png
Binary files differ
diff --git a/docs/html/auto/images/assets/do_02_music.png b/docs/html/auto/images/assets/do_02_music.png
new file mode 100644
index 0000000..59fc8df
--- /dev/null
+++ b/docs/html/auto/images/assets/do_02_music.png
Binary files differ
diff --git a/docs/html/auto/images/assets/do_03_more.png b/docs/html/auto/images/assets/do_03_more.png
new file mode 100644
index 0000000..17040d1
--- /dev/null
+++ b/docs/html/auto/images/assets/do_03_more.png
Binary files differ
diff --git a/docs/html/auto/images/assets/do_04_mdrawer.png b/docs/html/auto/images/assets/do_04_mdrawer.png
new file mode 100644
index 0000000..de94c22
--- /dev/null
+++ b/docs/html/auto/images/assets/do_04_mdrawer.png
Binary files differ
diff --git a/docs/html/auto/images/assets/do_05_template.png b/docs/html/auto/images/assets/do_05_template.png
new file mode 100644
index 0000000..4e11243
--- /dev/null
+++ b/docs/html/auto/images/assets/do_05_template.png
Binary files differ
diff --git a/docs/html/auto/images/assets/do_06_gdrawer.png b/docs/html/auto/images/assets/do_06_gdrawer.png
new file mode 100644
index 0000000..b02c0e6
--- /dev/null
+++ b/docs/html/auto/images/assets/do_06_gdrawer.png
Binary files differ
diff --git a/docs/html/auto/images/assets/do_07_notif.png b/docs/html/auto/images/assets/do_07_notif.png
new file mode 100644
index 0000000..50ea565
--- /dev/null
+++ b/docs/html/auto/images/assets/do_07_notif.png
Binary files differ
diff --git a/docs/html/auto/images/carlogos.png b/docs/html/auto/images/carlogos.png
deleted file mode 100644
index 3522aa3..0000000
--- a/docs/html/auto/images/carlogos.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/figure02.png b/docs/html/auto/images/figure02.png
deleted file mode 100644
index 1b87224..0000000
--- a/docs/html/auto/images/figure02.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/figure03.png b/docs/html/auto/images/figure03.png
deleted file mode 100644
index 0c4e20d..0000000
--- a/docs/html/auto/images/figure03.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/figure04.png b/docs/html/auto/images/figure04.png
deleted file mode 100644
index 3e9c894..0000000
--- a/docs/html/auto/images/figure04.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/figure05.png b/docs/html/auto/images/figure05.png
deleted file mode 100644
index 9c1d9b8..0000000
--- a/docs/html/auto/images/figure05.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/figure06.png b/docs/html/auto/images/figure06.png
deleted file mode 100644
index 8140f0c..0000000
--- a/docs/html/auto/images/figure06.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/figure07.png b/docs/html/auto/images/figure07.png
deleted file mode 100644
index 82c1c76..0000000
--- a/docs/html/auto/images/figure07.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/figure08.png b/docs/html/auto/images/figure08.png
deleted file mode 100644
index f11e3a8..0000000
--- a/docs/html/auto/images/figure08.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/auto/images/hero.jpg b/docs/html/auto/images/hero.jpg
index 3f9114f..34b5b5d 100644
--- a/docs/html/auto/images/hero.jpg
+++ b/docs/html/auto/images/hero.jpg
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/iheartradio.png b/docs/html/auto/images/logos/apps/iheartradio.png
new file mode 100644
index 0000000..8feb38d
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/iheartradio.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/joyride.png b/docs/html/auto/images/logos/apps/joyride.png
new file mode 100644
index 0000000..8c2897e
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/joyride.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/mlb.png b/docs/html/auto/images/logos/apps/mlb.png
new file mode 100644
index 0000000..ddde4cd
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/mlb.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/pandora.png b/docs/html/auto/images/logos/apps/pandora.png
new file mode 100644
index 0000000..13fa1d3
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/pandora.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/pocketcasts.png b/docs/html/auto/images/logos/apps/pocketcasts.png
new file mode 100644
index 0000000..5227937
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/pocketcasts.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/songza.png b/docs/html/auto/images/logos/apps/songza.png
new file mode 100644
index 0000000..3bd7107
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/songza.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/spotify.png b/docs/html/auto/images/logos/apps/spotify.png
new file mode 100644
index 0000000..d039fd3
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/spotify.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/stitcher.png b/docs/html/auto/images/logos/apps/stitcher.png
new file mode 100644
index 0000000..b77da12
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/stitcher.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/tunein.png b/docs/html/auto/images/logos/apps/tunein.png
new file mode 100644
index 0000000..137ba81
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/tunein.png
Binary files differ
diff --git a/docs/html/auto/images/logos/apps/umano.png b/docs/html/auto/images/logos/apps/umano.png
new file mode 100644
index 0000000..7b59f95
--- /dev/null
+++ b/docs/html/auto/images/logos/apps/umano.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/acura.png b/docs/html/auto/images/logos/auto/acura.png
new file mode 100644
index 0000000..4ba69cc
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/acura.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/audi.png b/docs/html/auto/images/logos/auto/audi.png
new file mode 100644
index 0000000..9b99efe
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/audi.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/bentley.png b/docs/html/auto/images/logos/auto/bentley.png
new file mode 100644
index 0000000..ed8cf47
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/bentley.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/chevrolet.png b/docs/html/auto/images/logos/auto/chevrolet.png
new file mode 100644
index 0000000..e0980b0
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/chevrolet.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/chrysler.png b/docs/html/auto/images/logos/auto/chrysler.png
new file mode 100644
index 0000000..f366cba
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/chrysler.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/datsun.png b/docs/html/auto/images/logos/auto/datsun.png
new file mode 100644
index 0000000..059ffd8
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/datsun.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/fiat.png b/docs/html/auto/images/logos/auto/fiat.png
new file mode 100644
index 0000000..aaa5cf3
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/fiat.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/honda.png b/docs/html/auto/images/logos/auto/honda.png
new file mode 100644
index 0000000..62ee38f
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/honda.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/hyundai.png b/docs/html/auto/images/logos/auto/hyundai.png
new file mode 100644
index 0000000..4744641
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/hyundai.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/infinity.png b/docs/html/auto/images/logos/auto/infinity.png
new file mode 100644
index 0000000..ad77351
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/infinity.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/kia.png b/docs/html/auto/images/logos/auto/kia.png
new file mode 100644
index 0000000..f8046d9
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/kia.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/maserati.png b/docs/html/auto/images/logos/auto/maserati.png
new file mode 100644
index 0000000..22bcf6a
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/maserati.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/mazda.png b/docs/html/auto/images/logos/auto/mazda.png
new file mode 100644
index 0000000..2281c90
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/mazda.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/mercedesbenz.png b/docs/html/auto/images/logos/auto/mercedesbenz.png
new file mode 100644
index 0000000..05fab0f
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/mercedesbenz.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/mitsubishi.png b/docs/html/auto/images/logos/auto/mitsubishi.png
new file mode 100644
index 0000000..1405b19
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/mitsubishi.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/nissan.png b/docs/html/auto/images/logos/auto/nissan.png
new file mode 100644
index 0000000..63bc4f7
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/nissan.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/opel.png b/docs/html/auto/images/logos/auto/opel.png
new file mode 100644
index 0000000..7e25ed5
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/opel.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/renault.png b/docs/html/auto/images/logos/auto/renault.png
new file mode 100644
index 0000000..65a4ae3
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/renault.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/seat.png b/docs/html/auto/images/logos/auto/seat.png
new file mode 100644
index 0000000..9802ccf
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/seat.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/skoda.png b/docs/html/auto/images/logos/auto/skoda.png
new file mode 100755
index 0000000..7bc06b0
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/skoda.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/subaru.png b/docs/html/auto/images/logos/auto/subaru.png
new file mode 100644
index 0000000..7407e61
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/subaru.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/suzuki.png b/docs/html/auto/images/logos/auto/suzuki.png
new file mode 100644
index 0000000..85fd7e5
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/suzuki.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/volkswagen.png b/docs/html/auto/images/logos/auto/volkswagen.png
new file mode 100644
index 0000000..febadf4
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/volkswagen.png
Binary files differ
diff --git a/docs/html/auto/images/logos/auto/volvo.png b/docs/html/auto/images/logos/auto/volvo.png
new file mode 100644
index 0000000..683af26
--- /dev/null
+++ b/docs/html/auto/images/logos/auto/volvo.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/alpine.png b/docs/html/auto/images/logos/hard/alpine.png
new file mode 100644
index 0000000..55f0e8a
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/alpine.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/clarion.png b/docs/html/auto/images/logos/hard/clarion.png
new file mode 100644
index 0000000..2288b99
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/clarion.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/cloudcar.png b/docs/html/auto/images/logos/hard/cloudcar.png
new file mode 100644
index 0000000..9e7e8b7
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/cloudcar.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/delphi.png b/docs/html/auto/images/logos/hard/delphi.png
new file mode 100644
index 0000000..a2a03de
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/delphi.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/freescale.png b/docs/html/auto/images/logos/hard/freescale.png
new file mode 100644
index 0000000..2909944
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/freescale.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/fujitsuten.png b/docs/html/auto/images/logos/hard/fujitsuten.png
new file mode 100644
index 0000000..70269e3
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/fujitsuten.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/harman.png b/docs/html/auto/images/logos/hard/harman.png
new file mode 100644
index 0000000..0fb295a
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/harman.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/jvc.png b/docs/html/auto/images/logos/hard/jvc.png
new file mode 100644
index 0000000..6a9c7ad
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/jvc.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/kenwood.png b/docs/html/auto/images/logos/hard/kenwood.png
new file mode 100644
index 0000000..3c80098
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/kenwood.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/lg.png b/docs/html/auto/images/logos/hard/lg.png
new file mode 100644
index 0000000..52feeff
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/lg.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/panasonic.png b/docs/html/auto/images/logos/hard/panasonic.png
new file mode 100644
index 0000000..b6aaaf1
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/panasonic.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/parrot.png b/docs/html/auto/images/logos/hard/parrot.png
new file mode 100644
index 0000000..d5bf41f
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/parrot.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/pioneer.png b/docs/html/auto/images/logos/hard/pioneer.png
new file mode 100644
index 0000000..307d71a
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/pioneer.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/renesas.png b/docs/html/auto/images/logos/hard/renesas.png
new file mode 100644
index 0000000..69ecab7
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/renesas.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/symphonyteleca.png b/docs/html/auto/images/logos/hard/symphonyteleca.png
new file mode 100644
index 0000000..0b3ebe5
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/symphonyteleca.png
Binary files differ
diff --git a/docs/html/auto/images/logos/hard/texasinstruments.png b/docs/html/auto/images/logos/hard/texasinstruments.png
new file mode 100644
index 0000000..87d80cb5
--- /dev/null
+++ b/docs/html/auto/images/logos/hard/texasinstruments.png
Binary files differ
diff --git a/docs/html/auto/index.jd b/docs/html/auto/index.jd
index c7a3a4e..09374ad 100644
--- a/docs/html/auto/index.jd
+++ b/docs/html/auto/index.jd
@@ -23,6 +23,82 @@
 #hero-height {
   height:calc(100% - 100px);
 }
+.img-logo {
+  margin:0 auto;
+  display:block;
+  margin-bottom:-28px !important;
+}
+.img-logo-thin {
+  margin:0 auto;
+  display:block;
+  margin-bottom:-55px !important;
+}
+.col-5 {
+  width:170px;
+}
+.auto-img-container-cols {
+  position:relative;
+  margin-bottom:25px;
+  margin-top:25px;
+}
+.auto-img-frame-cols {
+  z-index:2;
+  position:relative;
+}
+.auto-img-shot-cols {
+  position:absolute;
+  top:5px;
+  left:2px;
+  z-index:1;
+}
+</style>
+
+
+    <style>
+.fullpage>#footer,
+#jd-content>.content-footer.wrap {
+  display:none;
+}
+</style>
+
+<style>
+#footer {
+  display: none;
+}
+.content-footer {
+  display: none;
+}
+#hero-height {
+  height:calc(100% - 110px);
+}
+.img-logo {
+  margin:0 auto;
+  display:block;
+  margin-bottom:-28px !important;
+}
+.img-logo-thin {
+  margin:0 auto;
+  display:block;
+  margin-bottom:-55px !important;
+}
+.col-5 {
+  width:170px;
+}
+.auto-img-container-cols {
+  position:relative;
+  margin-bottom:25px;
+  margin-top:25px;
+}
+.auto-img-frame-cols {
+  z-index:2;
+  position:relative;
+}
+.auto-img-shot-cols {
+  position:absolute;
+  top:5px;
+  left:2px;
+  z-index:1;
+}
 </style>
 
 
@@ -40,13 +116,14 @@
                 <div class="landing-h1 hero">Android Auto</div>
                 <div class="landing-subhead hero">Entertainment and services on your dashboard</div>
                 <div class="landing-hero-description">
-                  <p>Display and control your handheld app in vehicles.
+                  <p style="width:450px">Display and control your handheld app in vehicles.
                   Build apps with easy-to-use UI templates that
                   let users keep their eyes on the road.</p>
                 </div>
 
               <div class="landing-body">
-                <a href="{@docRoot}auto/overview.html" class="landing-button landing-primary" style="margin-top: 40px;">
+                <a href="{@docRoot}auto/overview.html" class="landing-button landing-primary"
+                   style="margin-top:40px;">
                   Developer Overview
                 </a>
               </div>
@@ -67,21 +144,33 @@
 
       <div class="landing-section landing-gray-background" id="android-in-car">
         <div class="wrap">
-          <div class="landing-section-header">
-            <div class="landing-h1">Bringing Android to Your Car</div>
+          <div class="landing-section-h1">
+            <div class="landing-h1">Extending Android to Cars</div>
           </div>
-
           <div class="landing-body">
-            <p>When users connect their Android phone to an Android Auto enabled vehicle, the
-              system shows an interface that lets users select compatible apps and services to run.
-            </p>
-            <p>Android Auto provides new APIs and tools that your existing Android apps can
-              leverage to run on any compatible vehicle. Users interact with your apps through the
-              touch screen and the physical buttons on the vehicle’s dashboard. Your apps can also
-              respond to voice commands.
+            <div class="landing-subhead">Android Auto brings the Android experience to
+            cars with apps like Google Now and Maps.</div>
+            <div class="cols">
+              <div class="col-8">
+                <div class="auto-img-container-cols">
+                  <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+                  <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/01_b_now.png" />
+                </div>
+              </div>
+              <div class="col-8">
+                <div class="auto-img-container-cols">
+                  <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+                  <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/01_a_maps.png" />
+                </div>
+              </div>
+            </div>
+
+            <p>When users connect their Android phones to compatible vehicles, Android Auto
+             shows a standard interface that lets them start enabled apps and services.
+             Android Auto locks the handheld device when connected, so drivers
+            interact with Auto by using the vehicle's input controls, touch display, and voice.</p>
             </p>
           </div>
-
         </div> <!-- end .wrap -->
       </div> <!-- end .landing-section -->
 
@@ -89,74 +178,70 @@
       <div class="landing-section">
         <div class="wrap">
           <div class="landing-section-header">
-            <div class="landing-h1">One Platform</div>
+            <div class="landing-h1">Build for One Platform</div>
+            <div class="landing-subhead">Create apps with the Android APIs you're familiar with
+            and extend them to cars with the Auto SDK.
+            </div>
           </div>
 
           <div class="landing-body">
-            <p>Android Auto is an extension of the Android platform. You can easily adapt
-            existing apps for Android Auto and reuse many of the Android APIs and services you
-            are already familiar with.</p>
-            <p>The Android Auto platform and SDK let you write your apps only once, without having
+
+            <div class="cols">
+              <div class="col-8">
+                <div class="auto-img-container-cols">
+                  <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+                  <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/02_b_switcher.gif" />
+                </div>
+              </div>
+              <div class="col-8">
+                <div class="auto-img-container-cols">
+                  <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+                  <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/02_a_notif.gif" />
+                </div>
+              </div>
+            </div>
+            <p>Write your apps without having
             to worry about vehicle-specific hardware differences like screen resolution, software
-            interfaces, knobs and touch controls. Your app runs the same on any compatible
-            vehicle.</p>
+            interfaces, knobs, and touch controls. Your users get the same experience on any compatible
+            vehicle such as a consistent app launcher and system events such as notifications.</p>
           </div>
         </div> <!-- end .wrap -->
       </div> <!-- end .landing-section -->
 
-      <div class="landing-section landing-gray-background" >
+
+      <div class="landing-section landing-gray-background">
         <div class="wrap">
           <div class="landing-section-header">
-            <div class="landing-h1">Minimizing Distraction</div>
+            <div class="landing-h1">Minimize Distraction</div>
+            <div class="landing-subhead">
+             Standard UI templates for several app categories let users focus on the road. 
+            </div>       
           </div>
-
           <div class="landing-body">
-            <p>We designed Android Auto to minimize driver distraction. Android Auto provides UI
-              templates for several app categories. These templates define the user interaction model
-              for any app and follow international best practices for reducing driver distraction.</p>
-            <p>You can customize these templates to fit your brand and link them to your app’s
-              content and functionality, instead of building new UIs and testing them for driver
-              distraction, which is a lengthy and costly process.</p>
-            <p>Android Auto locks any device that users connect to a compatible vehicle, so drivers
-              interact with the device using voice actions and the vehicle’s input controls.</p>
+            <div class="cols">
+              <div class="col-8">
+                <div class="auto-img-container-cols">
+                  <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+                  <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/03_b_voice.gif" />
+                </div>
+              </div>
+              <div class="col-8">
+                <div class="auto-img-container-cols">
+                  <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+                  <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/03_a_musict.png" />
+                </div>
+              </div>
+            </div>
+            <p>These templates define the user interaction model for all
+             apps and let you hook into a standard UI with touch and voice controls. The templates
+             meet international best practices for reducing driver
+             distraction while still letting you customize and brand them to properly deliver your
+             content.
+             </p>
           </div>
         </div> <!-- end .wrap -->
       </div> <!-- end .landing-section -->
 
-      <div class="landing-section landing-white-background">
-        <div class="wrap">
-          <div class="landing-section-header">
-            <div class="landing-h1">Building an Ecosystem</div>
-          </div>
-          <div class="landing-body landing-align-center">
-              <p style="margin-bottom:20px">
-                Android Auto is coming soon to new cars from these manufacturers:
-              </p>
-          </div>
-          <div style="width:800px;margin:0 auto">
-            <img src="{@docRoot}auto/images/carlogos.png" alt="Partners" />
-          </div>
-        </div> <!-- end .wrap -->
-      </div> <!-- end .landing-section -->
-
-
-      <div class="landing-section" >
-        <div class="wrap">
-          <div class="landing-section-header">
-            <div class="landing-h1">Developer Stories</div>
-          </div>
-
-          <div class="landing-body">
-            <p>We're working with developers to bring many popular apps to Android Auto:</p>
-            <p>
-
-            </p>
-          </div>
-
-        </div> <!-- end .wrap -->
-      </div> <!-- end .landing-section -->
-
-
       <div class="landing-section" style="background-color:#f5f5f5">
         <div class="wrap">
           <div class="landing-section-header">
@@ -180,8 +265,7 @@
               <a target="_blank" href="http://g.co/androidautodev">
                 <img class="landing-social-image" src="//www.google.com/images/icons/product/gplus-128.png" alt="+Android Auto Developers">
               </a>
-              <p style="margin-bottom:5px">G+ Community</p>
-              <p class="landing-small">
+              <p>
                 Join the Android Auto developer community on Google+ to stay involved, get the
                 latest updates, and exchange experiences with other developers.
                 <a target="_blank" href="http://g.co/androidautodev">+Android Auto Developers</a>
@@ -191,6 +275,299 @@
         </div> <!-- end .wrap -->
       </div> <!-- end .landing-section -->
 
+
+
+      <div class="landing-section landing-gray-background" >
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">See What Others Have Done</div>
+            <div class="landing-subhead">We're working with developers to bring many popular apps
+            to Android Auto</div>
+          </div>
+          <div class="landing-body">
+          <div class="cols">
+
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/joyride.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/mlb.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/pandora.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/pocketcasts.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+          </div>
+          <div class="cols">
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/songza.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/stitcher.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/tunein.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+            <div class="col-4">
+              <img src="{@docRoot}auto/images/logos/apps/umano.png"
+                   width="160" height="160" class="img-logo" />
+            </div>
+          </div>
+          <div class="cols" style="margin-top:40px">
+             <div class="col-4">
+                <img src="{@docRoot}auto/images/logos/apps/iheartradio.png"
+                     width="160" height="160" class="img-logo" />
+              </div>
+              <div class="col-12">
+                <p><em>
+                "The Android Auto APIs provide an easy way to integrate the most important features and functionality of iHeartRadio’s robust music service into a safety-minded automotive infotainment solution. The process was seamless, utilizing a flexible construct that allowed us to quickly adapt our existing product without losing any of the core experience our listeners know and love."</em></p>
+
+                <b>Ryan Goff<br>
+                Director of Automotive Integrations for Clear Channel Media and Entertainment</b>
+              </div>
+          </div>
+          <div class="cols" style="margin-top:60px">
+
+              <div class="col-4">
+                <img src="{@docRoot}auto/images/logos/apps/spotify.png"
+                     width="160" height="160" class="img-logo" />
+              </div>
+              <div class="col-12"><p style="margin-top:20px"><em>
+              "Android Auto offers Spotify the exciting opportunity to easily enable safe access to millions of songs while driving. We were able to quickly develop for the platform using the new Android voice and media API extensions. As a result, Android users will soon be able to continue the Spotify experience in their cars, including being able to play any song, artist, album or playlist by voice.</em></p>
+              </div>
+          </div>
+        </div>
+
+      </div> <!-- end .wrap -->
+    </div> <!-- end .landing-section -->
+
+
+
+      <div class="landing-section landing-white-background">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h1">Building an Ecosystem</div>
+          </div>
+          <div class="landing-body landing-align-center">
+              <div class="landing-subhead">
+                Android Auto is coming soon to new cars from these manufacturers
+              </div>
+          </div>
+          <div class="cols">
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/acura.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/audi.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/bentley.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/chevrolet.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/chrysler.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+          </div>
+          <div class="cols">
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/datsun.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/fiat.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/honda.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/hyundai.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/infinity.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+          </div>
+          <div class="cols">
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/kia.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/maserati.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/mazda.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/mercedesbenz.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/mitsubishi.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+          </div>
+          <div class="cols">
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/nissan.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/opel.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/renault.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/seat.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/skoda.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+          </div>
+          <div class="cols">
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/subaru.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/suzuki.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/volkswagen.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/auto/volvo.png"
+                   width="120" height="120" class="img-logo" />
+            </div>
+            <div class="col-5">
+              <!--<img src="/auto/images/logos/auto/skoda.png"
+                   width="120" height="120" class="img-logo" />-->
+            </div>
+          </div>
+
+          <div class="landing-body landing-align-center">
+              <div class="landing-subhead" style="margin-top:80px">
+                Android Auto is also coming soon to aftermarket systems from these manufacturers:
+              </div>
+          </div>
+          <div class="cols">
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/alpine.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/clarion.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/cloudcar.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/delphi.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/freescale.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+          </div>
+          <div class="cols">
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/fujitsuten.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/harman.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/jvc.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/kenwood.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/lg.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+          </div>
+          <div class="cols">
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/panasonic.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/parrot.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/pioneer.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/renesas.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/symphonyteleca.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+          </div>
+          <div class="cols">
+            <div class="col-5">
+              <img src="{@docRoot}auto/images/logos/hard/texasinstruments.png"
+                   width="120" height="120" class="img-logo-thin" />
+            </div>
+            <div class="col-5">
+              <!--<img src="/auto/images/logos/hard/.png"
+                   width="120" height="120" class="img-logo-thin" />-->
+            </div>
+            <div class="col-5">
+              <!--<img src="/auto/images/logos/hard/.png"
+                   width="120" height="120" class="img-logo-thin" />-->
+            </div>
+            <div class="col-5">
+              <!--<img src="/auto/images/logos/hard/.png"
+                   width="120" height="120" class="img-logo-thin" />-->
+            </div>
+            <div class="col-5">
+              <!--<img src="/auto/images/logos/hard/.png"
+                   width="120" height="120" class="img-logo-thin" />-->
+            </div>
+          </div>
+        </div> <!-- end .wrap -->
+      </div> <!-- end .landing-section -->
     </div> <!-- end .landing-rest-of-page -->
 
 
@@ -205,7 +582,7 @@
         Except as noted, this content is
         licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
         Creative Commons Attribution 2.5</a>. For details and
-        restrictions, see the <a href="/license.html">Content
+        restrictions, see the <a href="{@docRoot}license.html">Content
         License</a>.
       </div>
     </div>
diff --git a/docs/html/auto/overview.jd b/docs/html/auto/overview.jd
index 8748bff..728dff7 100644
--- a/docs/html/auto/overview.jd
+++ b/docs/html/auto/overview.jd
@@ -13,6 +13,49 @@
 #copyright {
     margin-top:-35px;
 }
+.auto-img-container {
+  position:relative;
+}
+.auto-img-frame {
+  z-index:2;
+  position:relative;
+}
+.auto-img-shot {
+  position:absolute;
+  top:9px;
+  left:8px;
+  z-index:1;
+}
+.auto-img-container-cols {
+  position:relative;
+  margin-top:10px;
+}
+.auto-img-frame-cols {
+  z-index:2;
+  position:relative;
+}
+.auto-img-shot-cols {
+  position:absolute;
+  top:0px;
+  left:0px;
+  z-index:1;
+  border:1px solid #;
+  -webkit-border-radius: 7px;
+  -moz-border-radius: 7px;
+  border-radius: 7px;
+}
+.auto-col-2 {
+  width:380px;
+  display: inline;
+  float: left;
+  margin-left: 10px;
+  margin-right: 10px;
+}
+.auto-img-container-single {
+  width:380px;
+  margin:0 auto;
+  margin-top:20px;
+}
 </style>
 
 <div style="width:780px; margin:0 auto;">
@@ -79,13 +122,13 @@
 Android Auto experience on a regular Android device.</p>
 
 
-<h2 id="design" style="margin-top:30px">Design</h2>
+<h2 id="design">Design</h2>
 
 <p>Digital experiences for cars should complement and augment driving, not demand the driver's
 attention. Designing these experiences for cars is fundamentally different than in the case of
 phones and tablets. It requires rethinking how these experiences unfold.</p>
 
-<h3 id="designprinciples" style="margin-top:25px">Design Principles</h3>
+<h3 id="designprinciples">Design Principles</h3>
 
 <p><strong>Glanceable</strong>. We designed Android Auto to reduce UI complexity, optimize user
 interactions, and lower cognitive load. Effective apps show just enough information
@@ -105,52 +148,15 @@
 system, creating a truly integrated experience in every car. By using the vehicle's screen and
 controls, apps feel tailored to each car.</p>
 
-<h3 id="uioverview" style="margin-top:25px">UI Overview</h3>
-
-<p>Android Auto is a new environment that leverages existing UI models where appropiate and adds
-new models based on constrains and context. There are three primary concepts for Android Auto:
-<strong>Suggest</strong>, a unified place for predictive content; <strong>Demand</strong>, a
-pervasive way to interact with voice; and the <strong>Facets</strong>, organized spaces for
-primary activities, apps and content.</p>
-
-<dl>
-<dt style="margin-bottom:10px"><strong>Suggest: The Google Facet</strong></dt>
-<dd style="margin-bottom:20px">
-Core of continuity and extensibility is contextual stream of Now-like cards, powered by your
-apps and notifications. Relevant, timely, and dynamic, the stream organizes likely people, media,
-places, and information so drivers can quickly continue their activities or start something new.
-Google Now and notifications enable drivers to use the apps and services they know when they are
-most relevant.
-</dd>
-<dt style="margin-bottom:10px"><strong>Demand: The Voice Layer</strong></dt>
-<dd style="margin-bottom:20px">
-Voice-enabled tasks lets drivers accomplish their goals without taking their eyes off the road.
-Android Auto defines actions and intents that your app can register for.
-These are accessible through both persistent UI elements and dedicated hardware controls.
-</dd>
-<dt style="margin-bottom:10px"><strong>Facets and Templates: App-powered activities</strong></dt>
-<dd style="margin-bottom:20px">
-In the car, pages of app icons and different UIs create a distracting and dangerous situation.
-Instead, Android Auto apps power templates which help provide simple but customizable UIs
-for common interactions such as media or communications. Templates incorporate common behaviors,
-such as play/pause or reply to a message, while still letting your app promote its value
-and its brand. Apps are organized into facets (or activities) to enable quick access.
-</dd>
-</dl>
-
-<p>Android Auto uses the input and output mechanisms in each vehicle to tailor the interactions.
-Some vehicles have dedicated hardware controls, while others have primarily touch-based systems.
-Android Auto maps common actions and intents across these diverse sets of controls and outputs to
-enable you to concentrate on your unique app experience.</p>
 
 
-<h2 id="architecture" style="margin-top:30px">Architecture</h2>
+<h2 id="architecture">Architecture</h2>
 
 <p>The Android Auto app projects your app's customized UI on the vehicle's screen. To communicate
 with the Android Auto app, your media app implements a set of media interfaces.</p>
 
 <div style="width:750px;margin:0 auto">
-<img src="/auto/images/figure01.png" alt="" id="figure1" />
+<img src="{@docRoot}auto/images/figure01.png" alt="" id="figure1" />
 <p class="img-caption">
   <strong>Figure 1</strong> - Architecture of Android Auto.
 </p>
@@ -180,7 +186,7 @@
 </ul>
 
 
-<h2 id="uitemplates" style="margin-top:30px">UI Templates</h2>
+<h2 id="uitemplates">UI Templates</h2>
 
 <p>The Android Auto app uses a templated UI to display content and user interaction
 opportunities. Android Auto provides you with a set of standard UI templates that follow
@@ -192,89 +198,98 @@
 media apps. Although you cannot change the standard template format or layout, you can customize
 the template colors, action icons, background images, and more.</p>
 
-<h3 id="launchapp" style="margin-top:25px">Launch App Template</h3>
+<h3 id="launchapp">Launch App Template</h3>
 
 <p>The Launcher template shows all the compatible media apps installed on the user’s
 Android device and lets users select one of them from an scrollable list:</p>
 
-<div style="width:500px;margin:0 auto">
-<img src="/auto/images/figure02.png" alt="" id="figure2" />
-<p class="img-caption">
-  <strong>Figure 2.</strong> The Launcher template.
-</p>
+<div class="auto-img-container-single">
+  <div class="auto-img-container">
+    <img class="auto-img-frame-cols" src="/auto/images/assets/00_frame.png" />
+    <img class="auto-img-shot-cols" src="/auto/images/assets/do_01_switcher.png" />
+  </div>
+  <p class="img-caption" style="margin-top:0px">
+    <strong>Figure 2.</strong> The Launcher template.
+  </p>
 </div>
 
-<h3 style="margin-top:25px">Primary App Template</h3>
+<h3>Primary App Template</h3>
 
 <p>After the user selects a media app, the display shows the primary app template. Figure
 3 shows the elements of this template that you can customize:</p>
 
-<div style="width:428px;margin:0 auto">
-<img src="/auto/images/figure03.png" alt="" id="figure3" />
-<p class="img-caption">
-  <strong>Figure 3.</strong> The main application template.
-</p>
-</div>
-
 <p>You can customize the primary app template to show your own icons, app name, and
 background images. Figure 4 shows an example of a customized template:</p>
 
-<div style="width:787px;margin:0 auto">
-<img src="/auto/images/figure04.png" alt="" id="figure4" />
+<div class="cols">
+<div class="auto-col-2">
+  <div class="auto-img-container-cols">
+    <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+    <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/do_05_template.png" />
+  </div>
+</div>
+<div class="auto-col-2">
+  <div class="auto-img-container-cols">
+    <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+    <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/do_02_music.png" />
+  </div>
+</div>
+</div>
 <p class="img-caption">
   <strong>Figure 4.</strong> A customized template.
 </p>
-</div>
 
-<h3 id="useractions" style="margin-top:25px">User Actions</h3>
+
+
+<h3 id="useractions">User Actions</h3>
 
 <p>The primary app template supports four main actions on the action bar, four auxiliary actions
 on the overflow bar, and the <em>Return</em> action. You can use standard controls and customize
 the actions and icons, as shown in Figure 5.</p>
 
-<div style="width:500px;margin:0 auto">
-<img src="/auto/images/figure05.png" alt="" id="figure5" />
-<p class="img-caption">
-  <strong>Figure 5.</strong> Custom icons for auxiliary actions.
-</p>
+<div class="auto-img-container-single">
+  <div class="auto-img-container">
+    <img class="auto-img-frame-cols" src="/auto/images/assets/00_frame.png" />
+    <img class="auto-img-shot-cols" src="/auto/images/assets/do_03_more.png" />
+  </div>
+  <p class="img-caption" style="margin-top:0px">
+    <strong>Figure 5.</strong> Custom extra actions.
+  </p>
 </div>
 
-<h3 id="drawertransitions" style="margin-top:25px">Drawer Transitions</h3>
+<h3 id="drawertransitions">Drawer Transitions</h3>
 
 <p>For browse actions, the display shows the drawer transition and template:</p>
 
-<div style="width:750px;margin:0 auto">
-<img src="/auto/images/figure06.png" alt="" id="figure6" />
-<p class="img-caption">
-  <strong>Figure 6.</strong> The drawer transition.
-</p>
-</div>
-
 <p>After the transition from the primary app template to the drawer template, the drawer
 appears on the center. The customized drawer template shows the media containers and
 media files provided by the media service in your app. You can also customize drawers
 with icons for list items.</p>
 
-<div style="width:500px;margin:0 auto">
-<img src="/auto/images/figure07.png" alt="" id="figure7" />
-<p class="img-caption">
-  <strong>Figure 7.</strong> A customized drawer template.
-</p>
+<div class="cols">
+<div class="auto-col-2">
+  <div class="auto-img-container-cols">
+    <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+    <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/do_06_gdrawer.png" />
+  </div>
 </div>
+<div class="auto-col-2">
+  <div class="auto-img-container-cols">
+    <img class="auto-img-frame-cols" src="{@docRoot}auto/images/assets/00_frame.png" />
+    <img class="auto-img-shot-cols" src="{@docRoot}auto/images/assets/do_04_mdrawer.png" />
+  </div>
+</div>
+</div>
+<p class="img-caption">
+  <strong>Figure 4.</strong> Generic and customized drawer templates.
+</p>
 
-<h3 id="daynighttransitions" style="margin-top:25px">Day and Night Transitions</h3>
+<h3 id="daynighttransitions">Day and Night Transitions</h3>
 
 <p>All the templates support different color schemes for day and night, as shown in
 Figure 8. The platform provides the state (day or night) and makes adjustments automatically.</p>
 
-<div style="width:780px;margin:0 auto">
-<img src="/auto/images/figure08.png" alt="" id="figure8" />
-<p class="img-caption">
-  <strong>Figure 8.</strong> Day and night transitions.
-</p>
-</div>
-
-<h3 id="customizetemplates" style="margin-top:25px">Customizing Templates</h3>
+<h3 id="customizetemplates">Customizing Templates</h3>
 
 <p>To customize the templates, provide the following app-specific resources and actions
 to the Android Auto media client.</p>
@@ -288,7 +303,7 @@
 <p>If provided, the media client automatically uses them in the templated UI.</p>
 
 
-<h2 id="devprocess" style="margin-top:30px">Development Process</h2>
+<h2 id="devprocess">Development Process</h2>
 
 <p class="note"><strong>Note:</strong> When released, the Android Auto SDK will provide
 media service interfaces, an APK for handheld devices that simulates the Android Auto
@@ -327,7 +342,7 @@
 controls.</p>
 
 
-<h2 id="emulator" style="margin-top:30px">Testing Your App on an Android Device</h2>
+<h2 id="emulator">Testing Your App on an Android Device</h2>
 
 <p>The Android Auto SDK includes an APK with a media client implementation, which is
 similar to those available in compatible vehicles. To test your app with this
@@ -348,7 +363,7 @@
 in the UI controls.</p>
 
 
-<h2 id="running" style="margin-top:30px">Running Your App on Android Auto</h2>
+<h2 id="running">Running Your App on Android Auto</h2>
 
 <p>Media apps are available on the Google Play Store for compatible Android devices.
 When users connect their Android device to a compatible vehicle, the
diff --git a/docs/html/distribute/essentials/essentials_toc.cs b/docs/html/distribute/essentials/essentials_toc.cs
index 7084fdd..d0a1114 100644
--- a/docs/html/distribute/essentials/essentials_toc.cs
+++ b/docs/html/distribute/essentials/essentials_toc.cs
@@ -11,12 +11,6 @@
     </div>
   </li>
   <li class="nav-section">
-    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/gpfe-guidelines.html">
-          <span class="en">Education Guidelines</span>
-        </a>
-    </div>
-  </li>
-  <li class="nav-section">
     <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/optimizing-your-app.html">
           <span class="en">Optimize Your App</span>
         </a>
diff --git a/docs/html/distribute/essentials/gpfe-guidelines.jd b/docs/html/distribute/essentials/gpfe-guidelines.jd
deleted file mode 100644
index 734bddc..0000000
--- a/docs/html/distribute/essentials/gpfe-guidelines.jd
+++ /dev/null
@@ -1,509 +0,0 @@
-page.title=Education Guidelines
-page.metaDescription=These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.
-page.image=/distribute/images/edu-guidelines.jpg
-Xnonavpage=true
-
-@jd:body
-
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Guidelines</h2>
-<ol>
-<li><a href="#basic-reqts">Basic Requirements</a></li>
-<li><a href="#monetizing-ads">Monetizing and Ads</a></li>
-<li><a href="#e-value">Educational Value</a></li>
-<li><a href="#quality">App Quality</a></li>
-<li><a href="#related-resources">Related Resources</a></li>
-</ol>
-
-<h2>
-  Testing
-</h2>
-
-<ol>
-  <li>
-    <a href="#test-environment">Setting Up a Test Environment</a>
-  </li>
-</ol>
-
-</div></div>
-
-<div style="margin:0 0 1em 0;">
-  <img src="{@docRoot}distribute/images/edu-guidelines.jpg" style=
-  "width:274px;">
-</div>
-
-<p>
-  These guidelines and requirements help you develop great apps for students,
-  which offer compelling content and an intuitive user experience on Android
-  tablets.
-</p>
-
-<p>
-  You’ll also need to ensure that your apps comply with the terms of the
-  <a href=
-  "https://play.google.com/about/developer-distribution-agreement-addendum.html">
-  Google Play for Education Addendum</a>, <a href=
-  "http://play.google.com/about/developer-content-policy.html">Google Play
-  Developer Program Policies</a>, and <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html">Developer
-  Distribution Agreement</a>.
-</p>
-
-<div class="headerLine">
-  <h2 id="basic-reqts">
-    Basic Requirements
-  </h2>
-
-
-</div>
-
-<p>
-  To participate, your apps must be designed for the K-12 market. The basic
-  requirements that your apps must meet are:
-</p>
-
-<ul>
-  <li>
-    <p>
-      Apps and the ads they contain must not collect personally identifiable
-      information, other than user credentials or data required to operate and
-      improve the app.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      Apps must not use student data for purposes unrelated to its educational
-      function.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      Apps must have a content rating of "Everyone" or "Low Maturity" (apps
-      with a "Medium Maturity" rating are allowed, if they have that rating
-      solely because they allow communication between students).
-    </p>
-  </li>
-
-  <li>
-    <p>
-      App content, including ads displayed by the app, must be consistent with
-      the app's maturity rating. The app must not display any "offensive"
-      content, as described in the <a href=
-      "http://play.google.com/about/developer-content-policy.html">Google Play
-      Developer Program Policies</a> and <a href=
-      "https://support.google.com/googleplay/android-developer/answer/188189">content-rating
-      guidelines</a>.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      Apps must comply with the Children’s Online Privacy Protection Act and
-      all other applicable laws and regulations.
-    </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-  <h2 id="monetizing-ads">
-    Monetizing and Ads
-  </h2>
-
-
-</div>
-
-<p>
-  In-app purchase is currently not supported with Google Play for Education, so
-  a student device will block any transactions. To avoid confusion, be sure to
-  remove any in-app purchase buttons and related UI elements from your apps.
-  We’re investigating additional purchase mechanisms to enable more flexible
-  pricing models for developers and schools.
-</p>
-
-<p>
-  If your apps are priced In Google Play for Education, you must allow Google
-  Play to offer teachers limited free trials before purchase (you provide this
-  through business terms only, no development work is needed.)
-</p>
-
-<p>
-  You can only choose not to remove in-app purchasing from your apps where all
-  content and services are sold through Google Play for Education using In-app
-  Billing. If you choose not to remove In-app Billing features, ensure that:
-</p>
-
-<ul>
-  <li>
-    <p>
-      Users can access your apps’ core functionality for a classroom setting
-      without an in-app purchase.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      In-app purchases are clearly identifiable in your UI.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      You declare the use of in-app purchases at <a href=
-      "{@docRoot}distribute/googleplay/edu/start.html#publish">opt-in</a>.
-    </p>
-  </li>
-</ul>
-
-<p>
-  For each app that you publish, you can set a single price that applies to
-  both Google Play and Google Play for Education. You can’t set a different
-  price for a given app (based on a single package name) in Google Play for
-  Education.
-</p>
-
-<p>
-  If your apps display ads, you should disable the display of ads if possible,
-  or ensure that:
-</p>
-
-<ul>
-  <li>Ads are not distracting for students or teachers (this includes
-  Flash-based ads, video ads, and ads that flash or move)
-  </li>
-
-  <li>Interstitial ads are not served in the app
-  </li>
-
-  <li>Ad walls do not appear in the app UI
-  </li>
-
-  <li>Ads do not occupy a significant portion of the screen
-  </li>
-
-  <li>Ads content does not exceed the maturity rating of the app.
-  </li>
-
-  <li>
-    <p>
-      You declare the use of ads at <a href=
-      "{@docRoot}distribute/googleplay/edu/start.html#publish">opt-in</a>.
-    </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-  <h2 id="e-value">
-    Educational Value
-  </h2>
-
-
-</div>
-
-<div class="figure">
-  <img src="{@docRoot}images/gp-e-value.png" class="border-img">
-</div>
-
-<p>
-  Apps submitted to Google Play for Education will be evaluated by a
-  third-party educator network, which will review them based on alignment with
-  <a href="http://www.corestandards.org/">Common Core Standards</a> and other
-  educational considerations. This will help make your content more
-  discoverable for teachers and administrators as they browse by grade level,
-  subject, core curriculum, and other parameters.
-</p>
-
-<p>
-  Apps with highest educational value will have these characteristics:
-</p>
-
-<ul>
-  <li>
-    <p>
-      Designed for use in K-12 classrooms.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      Aligned with a common core standard or support common-core learning.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      Simple, easy to use, and intuitive for the grade levels the apps are
-      targeting. Apps are relatively easy to navigate without teacher guidance.
-      Not distracting or overwhelming to students.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      Enjoyable and interactive. Apps are engaging to students and lets them
-      control their experience.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      Versatile. Apps have features that make them useful for more than one
-      classroom function or lesson throughout the school year.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      Supports the "4Cs":
-    </p>
-
-    <ul>
-      <li>
-        <p>
-          <em>Creativity</em> &mdash; Allows students to create in order to
-          express understanding of the learning objectives, and try new
-          approaches, innovation, and invention to get things done.
-        </p>
-      </li>
-
-      <li>
-        <p>
-          <em>Critical thinking</em> &mdash; Allows students to look at
-          problems in a new way, linking learning across subjects and
-          disciplines.
-        </p>
-      </li>
-
-      <li>
-        <p>
-          <em>Collaboration</em> &mdash; Allows students and (if appropriate)
-          educators to work together to reach a goal.
-        </p>
-      </li>
-
-      <li>
-        <p>
-          <em>Communication</em> &mdash; Allows students to comprehend,
-          critique and share thoughts, questions, ideas, and solutions.
-        </p>
-      </li>
-    </ul>
-  </li>
-</ul>
-
-<p>
-  As you design and develop your apps, make sure they offer high educational
-  value by addressing as many of these characteristics as possible.
-</p>
-
-<div class="headerLine">
-  <h2 id="quality">
-    App Quality
-  </h2>
-
-
-</div>
-
-<div class="figure">
-  <img src="{@docRoot}images/gp-edu-quality.png">
-</div>
-
-<p>
-  Your apps should be designed to perform well and look great on Android
-  tablets, and they should offer the best user experience possible.
-</p>
-
-<p>
-  High quality apps are engaging, intuitive, and offer compelling content.
-  Google Play for Education will highlight high-quality apps for easy discovery
-  in the store. Here are some recommendations for making your app easy for
-  students and teachers to enjoy:
-</p>
-
-<ul>
-  <li>
-    <p>
-      Meet the Core Quality Guidelines:
-    </p>
-
-    <ul>
-      <li>
-        <p>
-          Follow <a href="{@docRoot}design/index.html">Android Design
-          Guidelines</a>. Pay special attention to the sections on <a href=
-          "{@docRoot}design/patterns/actionbar.html">Action Bar</a>, <a href=
-          "{@docRoot}design/patterns/navigation.html">Navigation</a>, and
-          <a href="{@docRoot}design/patterns/pure-android.html">Pure
-          Android</a>.
-        </p>
-      </li>
-
-      <li>
-        <p>
-          Test your apps against the <a href=
-          "{@docRoot}distribute/essentials/quality/core.html">Core Quality
-          Guidelines</a>.
-        </p>
-      </li>
-    </ul>
-  </li>
-
-  <li>
-    <p>
-      Meet the Tablet App Quality guidelines:
-    </p>
-
-    <ul>
-      <li>
-        <p>
-          Follow our best practices for tablet app development.
-        </p>
-      </li>
-
-      <li>
-        <p>
-          Review the <a href=
-          "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
-          Quality</a> guidelines and <a href=
-          "http://android-developers.blogspot.com/2012/11/designing-for-tablets-were-here-to-help.html">
-          blog post on designing for tablets.</a>
-        </p>
-
-        <ul>
-          <li>Check your Optimization Tips in the <a href=
-          "https://play.google.com/apps/publish/">Developer Console</a> (if
-          you've already uploaded your apps.)
-          </li>
-        </ul>
-      </li>
-
-      <li>
-        <p>
-          Strive for simplicity and highest usability for students:
-        </p>
-
-        <ul>
-          <li>
-            <p>
-              Design your app so that teachers and students can use all the
-              capabilities of your app without having to sign-in to multiple
-              accounts and remember multiple passwords.
-            </p>
-          </li>
-
-          <li>
-            <p>
-              Every student or teacher using a Google Play for Education tablet
-              will already be signed in with a Google account on the device.
-              You can take advantage of that to provide a simple, seamless
-              sign-in experience in your app. A recommended approach is to use
-              <a href="{@docRoot}google/play-services/auth.html">Google OAuth 2
-              authorization</a> through Google Play Services.
-            </p>
-          </li>
-        </ul>
-      </li>
-    </ul>
-  </li>
-</ul>
-
-<div class="headerLine">
-  <h2 id="test-environment">
-    Test Environment
-  </h2>
-
-
-</div>
-
-<p>
-  To test your app and assess it against the guidelines in this document, it's
-  recommended that you <a href=
-  "{@docRoot}distribute/essentials/quality/tablets.html#test-environment">set
-  up a test environment</a> that replicates the actual environment in which
-  students and teachers will run your app.
-</p>
-
-<h3>
-  Test conditions
-</h3>
-
-<p>
-  Make sure to test your apps under conditions that simulate those of schools.
-  For example, Google Play for Education lets administrators <a href=
-  "https://support.google.com/a/answer/182442?hl=en">control or disable certain
-  capabilities</a> for students, so it's good to test your app with those
-  capabilities disabled. Below are some conditions to test your apps for, to
-  ensure best results in the Google Play for Education environment:
-</p>
-
-<ul>
-  <li>
-    <p>
-      <em>Android version</em> &mdash; Test the apps on devices running Android
-      4.2. Google Play for Education devices will be running Android 4.2 or
-      higher (API level 17+).
-    </p>
-  </li>
-
-  <li>
-    <p>
-      <em>Proxy server</em> &mdash; Test the apps in a network environment that
-      uses proxies. Many schools use proxies.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      <em>No location services</em> &mdash; Test the apps to make sure they
-      work properly with location services disabled. Many schools will disable
-      location services for student devices.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      <em>No In-app Billing</em> &mdash; Test the apps to make sure they work
-      properly without access to In-app Billing. In-app purchases are blocked
-      on Google Play for Education devices.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      <em>No Bluetooth</em> &mdash; Test the apps to make sure they work
-      properly when Bluetooth is disabled. Many schools will disable Bluetooth
-      on student devices.
-    </p>
-  </li>
-
-  <li>
-    <p>
-      <em>No access to network</em> &mdash; Test the app to make sure it works
-      properly when the device cannot connect to the internet.
-    </p>
-  </li>
-</ul>
-
-<div class="headerLine">
-<h2>Related Resources</h2>
-</div>
-
-<div class="dynamic-grid">
-<h3>FOR DEVELOPERS</h3>
-
-<div class="resource-widget resource-flow-layout col-13"
-    data-query="collection:distribute/essentials/eduessentials/developers"
-    data-sortOrder="-timestamp"
-    data-cardSizes="6x3,6x3,6x3"
-    data-maxResults="6"></div>
-
-<h3>FOR TEACHERS AND EDUCATORS</h3>
-
-<div class="resource-widget resource-flow-layout col-13"
-    data-query="collection:distribute/essentials/eduessentials/educators"
-    data-sortOrder="-timestamp"
-    data-cardSizes="6x3,6x3,6x3"
-    data-maxResults="3"></div>
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/about.jd b/docs/html/distribute/googleplay/edu/about.jd
index e73356e..60d9402 100644
--- a/docs/html/distribute/googleplay/edu/about.jd
+++ b/docs/html/distribute/googleplay/edu/about.jd
@@ -9,7 +9,7 @@
 
 <p>
   Google Play for Education is an extension of Google Play designed for
-  schools. Here educators can discover apps approved by teachers for teachers,
+  schools. Here educators can discover Android and Chrome apps approved by teachers for teachers,
   as well as educational videos and a collection of classic books for their
   classroom.
 </p>
@@ -22,7 +22,7 @@
 </p>
 
 
-<div class="resource-widget resource-flow-layout col-13"
+<div class="resource-widget resource-flow-layout col-13" style="height:323px"
   data-query="collection:distribute/googleplay/gpfe/highlight"
   data-sortOrder="-timestamp"
   data-cardSizes="18x6,"
diff --git a/docs/html/distribute/googleplay/edu/faq.jd b/docs/html/distribute/googleplay/edu/faq.jd
deleted file mode 100644
index 36e2064..0000000
--- a/docs/html/distribute/googleplay/edu/faq.jd
+++ /dev/null
@@ -1,433 +0,0 @@
-page.title=Education FAQ
-meta.tags="gpfe, edu"
-page.metaDescription=Answers to frequent questions about Google Play for Education.
-page.image=/distribute/images/gpfe-faq.jpg
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-  <h2>
-    Topics
-  </h2>
-
-  <ol>
-    <li>
-    <a href="#business-model-and-monetization">Business Model and
-    Monetization</a>
-    </li>
-
-    <li>
-    <a href="#free-trials">Free Trials</a>
-    </li>
-
-    <li>
-    <a href="#discovery">Discovery</a>
-    </li>
-
-    <li>
-    <a href="#app-review-process">App Review Process</a>
-    </li>
-
-    <li>
-    <a href="#app-features">App Features</a>
-    </li>
-
-    <li>
-    <a href="#marketing-and-roi">Marketing and ROI</a>
-    </li>
-
-    <li>
-    <a href="#devices">Devices</a>
-    </li>
-
-    <li>
-    <a href="#accounts">Accounts</a>
-    </li>
-
-    <li>
-    <a href="#related-resources">Related Resources</a>
-    </li>
-  </ol>
-  </div>
-</div>
-
-<p>
-  This page provides answers to common questions that you might have about
-  Google Play for Education.
-</p>
-
-<div class="headerLine">
-  <h2 id="business-model-and-monetization">
-  Business Model and Monetization
-  </h2>
-
-
-</div>
-
-<p>
-  <strong>What is Google Play for Education?</strong>
-</p>
-
-<p>
-  Google Play for Education is a new online destination designed for schools.
-  Teachers can discover educational apps, books, and videos to meet the needs
-  of a single student, a classroom, or a whole district. Educators can browse
-  apps by grade, subject, keyword, or standard including Common Core State
-  Standards. Purchasing is done using a PO with no credit card required. Apps
-  are distributed to tablets instantly through the cloud.
-</p>
-
-<p>
-  <strong>Is Google Play for Education primarily for students or
-  educators?</strong>
-</p>
-
-<p>
-  The store on Google Play for Education is for educators, but its content is
-  for both educators and students. Teachers and administrators have the ability
-  to make purchases and control who within their school has access to the
-  purchase flows.
-</p>
-
-<div class="figure">
-  <img src="{@docRoot}distribute/images/gpfe-faq.jpg" style=
-  "width:480px;margin:1em 0em 1.5em 1.5em;">
-</div>
-
-<p>
-  <strong>Will Google Play for Education support subscription
-  purchases?</strong>
-</p>
-
-<p>
-  Currently, Google Play for Education supports one-time purchases. We’re
-  investigating additional purchase mechanisms to enable more flexible pricing
-  models for developers and schools.
-</p>
-
-<p>
-  <strong>Why is it recommended that in-app purchase features are
-  removed?</strong>
-</p>
-
-<p>
-  In-app Billing is currently not supported with Google Play for Education, and
-  a student device will block the Google Play transaction if a student attempts
-  to make an in-app purchase. To avoid confusing students, we recommend not
-  including any in-app purchase buttons and other UI in your apps. We’re
-  investigating additional purchase mechanisms to enable more flexible pricing
-  models for developers and schools.
-</p>
-
-<p>
-  <strong>Is Google Play for Education restricted so only its users can
-  purchase from the Google Play for Education? Or will anyone be able to
-  purchase from it?</strong>
-</p>
-
-<p>
-  Currently, only schools that are signed up for Google Play for Education can
-  make purchases on it.
-</p>
-
-<p>
-  <strong>Can I set different prices for my apps in Google Play for Education
-  and Google Play?</strong>
-</p>
-
-<p>
-  You set a single price for each app that applies to both Google Play and
-  Google Play for Education. You can’t set a different price for a given app
-  (based on a single package name) in Google Play for Education.
-</p>
-
-<div class="headerLine">
-  <h2 id="free-trials">
-  Free Trials
-  </h2>
-
-
-</div>
-
-<p>
-  <strong>Can I offer free trials through Google Play for Education?</strong>
-</p>
-
-<p>
-  Google Play for Education doesn't currently support free trials. If you want,
-  you can offer a free version of your app with limited functionality in Google
-  Play for Education, but that app would need to be separate from your paid app
-  and be reviewed separately for educational content.
-</p>
-
-<p>
-  <strong>Can I offer a free trial through Google Play's "In-app Subscriptions
-  with Free Trials" feature?</strong>
-</p>
-
-<p>
-  Google Play for Education doesn’t currently support In-app Billing or In-app
-  Subscriptions with free trials.
-</p>
-
-<div class="headerLine">
-  <h2 id="discovery">
-  Discovery
-  </h2>
-
-
-</div>
-
-<p>
-  <strong>What are the categories in Google Play for Education?</strong>
-</p>
-
-<p>
-  Google Play for Education includes categories for all grade levels from
-  Kindergarten to 12 and the following subjects: English Language Arts, World
-  Languages, Mathematics, Science, Social Science, Elective, Open Education
-  Resources (OER), and Tools.
-</p>
-
-<p>
-  <strong>I created an app specifically for Google Play for Education and don’t
-  want it to show up in Google Play. Is this possible?</strong>
-</p>
-
-<p>
-  Currently, it’s not possible to publish an app on Google Play for Education
-  and make it unavailable on Google Play.
-</p>
-
-<p>
-  <strong>If my app offers content for every level of education, how will it
-  fit the Common Core State Standard filters?</strong>
-</p>
-
-<p>
-  If your app applies to multiple levels of education, then the app will show
-  up in filtered results for multiple levels.
-</p>
-
-<div class="headerLine">
-  <h2 id="app-review-process">
-  App Review Process
-  </h2>
-
-
-</div>
-
-<p>
-  <strong>How are apps being reviewed? By whom and against what
-  criteria?</strong>
-</p>
-
-<p>
-  Apps are being reviewed by a third-party network of educators. These
-  educators assign the appropriate subject, grade, and Common Core State
-  Standards metadata, as well as evaluating whether the app meets the Google
-  Play for Education <a href=
-  "{@docRoot}distribute/essentials/gpfe-guidelines.html">criteria for classroom
-  use</a>.
-</p>
-
-<p>
-  <strong>How do I update my apps in Google Play for Education?</strong>
-</p>
-
-<p>
-  You can update your apps on Google Play for Education in the same manner you
-  do on Google Play. App updates will not be reviewed prior to being made
-  available through Google Play for Education. However, we will periodically
-  review updated apps for quality.
-</p>
-
-<p>
-  <strong>Does the app maturity rating reflect solely on what a user can do
-  within my Android app, or does the web version of my app influence the rating
-  as well?</strong>
-</p>
-
-<p>
-  The maturity rating that you set for an Android app refers only to the
-  content displayed in that app.
-</p>
-
-<div class="headerLine">
-  <h2 id="app-features">
-  App Features
-  </h2>
-
-
-</div>
-
-<p>
-  <strong>Do I need separate builds of my phone and tablet apps for Google Play
-  for Education, or is it the exact same app that lives on Google
-  Play?</strong>
-</p>
-
-<p>
-  We recommend you create one app and use it in both Google Play and Google
-  Play for Education.
-</p>
-
-<p>
-  <strong>What is the best way to get students’ work within apps sent back to
-  their teachers?</strong>
-</p>
-
-<p>
-  Teachers have mentioned that many apps achieve this by email from a third
-  party, which isn’t optimal for schools. As many schools use Google Apps for
-  Education, consider integrating your apps with Google Drive using the
-  <a href="https://developers.google.com/drive/about-sdk">SDK</a>.
-</p>
-
-<p>
-  <strong>How can developers test the teacher experience in Google Play for
-  Education? Is there a way to get an account to test it?</strong>
-</p>
-
-<p>
-  Currently, we are unable to provide developers with a test account to test
-  the Google Play for Education user experience. We’re investigating ways to
-  allow developers to simulate the environment.
-</p>
-
-<p>
-  <strong>If I already have an app in the Chrome Apps Pack will I get some help
-  migrating this to Android?</strong>
-</p>
-
-<p>
-  If you’d like to reach tablet users in schools we encourage you to build a
-  native app for the optimal user experience. Considerations for building your
-  apps can be found in the <a href=
-  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Google Play for
-  Education Guidelines</a>.
-</p>
-
-<div class="headerLine">
-  <h2 id="marketing-and-roi">
-  Marketing and ROI
-  </h2>
-
-
-</div>
-
-<p>
-  <strong>What are you doing to promote these apps to educators?</strong>
-</p>
-
-<p>
-  Google Play for Education is an extension of Google Play targeting schools
-  and making the discovery of educational apps easier. It helps your apps gain
-  visibility with the right audiences, without having to knock on school doors.
-  We’re constantly referring to the highest quality apps in our educator
-  outreach. We’ve also developed a series of collections to help educators
-  quickly browse apps for the most common use cases.
-</p>
-
-<p>
-  <strong>How many installs have similar apps had on Google Play for Education?
-  How much can I expect to make if I do an ROI analysis?</strong>
-</p>
-
-<p>
-  While we cannot disclose specific numbers, Google Play app listings provide
-  app download ranges for all apps.
-</p>
-
-<p>
-  <strong>What is the seasonality like for the education market? What are the
-  key timing considerations for app developers?</strong>
-</p>
-
-<p>
-  In the United States, school districts’ budget decisions go through a
-  planning phase in the Spring with budgets being released on July 1. We’ve
-  observed high purchase-volumes in the second quarter of the calendar year, to
-  use up end-of-year budgets. New budget purchases begin in the third quarter
-  of the calendar year.
-</p>
-
-<p>
-  <strong>Is there a way to offer a special deal, such as a discount, only on
-  Google Play for Education and not on Google Play?</strong>
-</p>
-
-<p>
-  No, this isn’t possible. Pricing, including special offers, must be the same
-  between Google Play for Education and Google Play.
-</p>
-
-<div class="headerLine">
-  <h2 id="devices">
-  Devices
-  </h2>
-
-
-</div>
-
-<p>
-  <strong>Which devices are available in the program? Will more be
-  available?</strong>
-</p>
-
-<p>
-  Nexus 7 is available for shipment now, and the Asus Transformer, HP Slate 8
-  Pro, and Galaxy Tab for Education will be available in early 2014. We look
-  forward to welcoming more Android devices into the Google in Education family
-  soon.
-</p>
-
-<p>
-  <strong>Can the devices be shared among many students?</strong>
-</p>
-
-<p>
-  No. Currently, this program is for one-to-one use. Each student can login to
-  one specific tablet that is allocated to them.
-</p>
-
-<div class="headerLine">
-  <h2 id="accounts">
-  Accounts
-  </h2>
-
-
-</div>
-
-<p>
-  <strong>Will an app know whether a user is a teacher or student?</strong>
-</p>
-
-<p>
-  No, the app has no mechanism for knowing if it’s running on a teacher’s
-  device or a student’s device. We recommend developers use their own user
-  database to enable this feature, where logins can be based on Google Account
-  information.
-</p>
-
-<p>
-  <strong>What log-in method do you recommend for an app on Google Play for
-  Education?</strong>
-</p>
-
-<p>
-  One of the key pieces of feedback we’ve heard multiple times from various
-  schools is that they prefer apps that offer Google Single Sign-on, so that
-  teachers and students don’t need to remember multiple log-in credentials. As
-  schools in the program use Google Accounts and Google Apps for Education,
-  offering Google Single Sign-on is ideal.
-</p>
-<div class="headerLine"><h2 id="related-resources">Related Resources</h2></div>
-
-<div class="resource-widget resource-flow-layout col-13"
-  data-query="collection:distribute/toolsreference/gpfefaq"
-  data-sortOrder="-timestamp"
-  data-cardSizes="6x3,6x3,6x3,9x3,9x3,9x3"
-  data-maxResults="6"></div>
-
diff --git a/docs/html/distribute/googleplay/edu/start.jd b/docs/html/distribute/googleplay/edu/start.jd
index 4886b5a..136611c 100644
--- a/docs/html/distribute/googleplay/edu/start.jd
+++ b/docs/html/distribute/googleplay/edu/start.jd
@@ -1,4 +1,4 @@
-page.title=Get Started with Education
+page.title=Publish Android Apps for Education
 page.image=/distribute/images/play-education.jpg
 meta.tags="education", "guidelines", "quality"
 page.tags="education", "addendum"
@@ -16,21 +16,23 @@
 </ol>
 </div></div>
 <p>
-  If you've got great apps for education and want to reach even more teachers
+  If you've got great Android apps for education and want to reach even more teachers
   and students, you can join the <strong>Google Play for Education</strong>
   program in a few simple steps. You do everything using the familiar tools and
   processes in Google Play.
 </p>
 
 <p>
-  Note that Google Play for Education is currently available to <strong>K-12
-  schools in the United States</strong> only.
+Note that Google Play for Education is currently available to <strong>K-12 schools in the United
+States</strong> only.</p>
+
+<p>If you have an educational Chrome app instead of an Android app, you can learn more about
+Chrome Apps in Google Play for Education at <a href=
+"https://developers.google.com/edu">developers.google.com/edu</a>.
 </p>
 
-<div class="center-img">
-  <img src="{@docRoot}images/gpfe-start-0.jpg" style=
-  "border:1px solid #ddd;padding:0px;width:100%;">
-</div>
+<img src="{@docRoot}images/gpfe-start-0.jpg" style=
+  "border:1px solid #ddd;padding:0px" width="760" height="403">
 
 <div class="headerLine">
   <h2 id="register">
diff --git a/docs/html/distribute/googleplay/googleplay_toc.cs b/docs/html/distribute/googleplay/googleplay_toc.cs
index 4196c39..36e424a 100644
--- a/docs/html/distribute/googleplay/googleplay_toc.cs
+++ b/docs/html/distribute/googleplay/googleplay_toc.cs
@@ -25,13 +25,7 @@
   </li>
   <li class="nav-section">
     <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/start.html">
-          <span class="en">Get Started with Education</span>
-        </a>
-    </div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/faq.html">
-          <span class="en">Education FAQ</span>
+          <span class="en">Publish Android Apps for Education</span>
         </a>
     </div>
   </li>
diff --git a/docs/html/google/play-services/index.jd b/docs/html/google/play-services/index.jd
index f5d4574..eec4f5a 100644
--- a/docs/html/google/play-services/index.jd
+++ b/docs/html/google/play-services/index.jd
@@ -11,10 +11,8 @@
 <div class="col-6">
 
   <h1 itemprop="name" style="margin-bottom:0;">Google Play Services</h1>
-  <p itemprop="description">
-  </p>
-
-  <p>Give your apps more features to attract users on a wider range of devices.
+  <p itemprop="description">Give your apps more features to attract users
+  on a wider range of devices.
   With Google Play services, your app can take advantage
   of the latest, Google-powered features such as Maps, Google+, and more,
   with automatic platform updates distributed as an APK through
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index ff08312..ea36405 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -373,6 +373,9 @@
             <li><a href="<?cs var:toroot ?>guide/topics/media/mediarouteprovider.html">
                   <span class="en">Media Route Provider</span></a>
                 </li>
+            <li><a href="<?cs var:toroot ?>guide/topics/media/exoplayer.html">
+                  <span class="en">ExoPlayer</span></a>
+                </li>
             <li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">
                    <span class="en">Supported Media Formats</span></a>
                 </li>
diff --git a/docs/html/guide/topics/media/exoplayer.jd b/docs/html/guide/topics/media/exoplayer.jd
new file mode 100644
index 0000000..17b4669
--- /dev/null
+++ b/docs/html/guide/topics/media/exoplayer.jd
@@ -0,0 +1,514 @@
+page.title=ExoPlayer
+page.tags="audio","video","adaptive","streaming","DASH","smoothstreaming"
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>In this document</h2>
+    <ol>
+      <li><a href="#overview">Overview</a></li>
+      <li><a href="#trackrenderer">TrackRenderer</a></li>
+      <li><a href="#samplesource">SampleSource</a>
+        <ol>
+          <li><a href="#mediaextractor">Providing media using MediaExtractor</a></li>
+          <li><a href="#adaptive-playback">Providing media for adaptive playback</a>
+            <ol>
+              <li><a href="#format-selection">Format selection for adaptive playback</a></li>
+            </ol>
+          </li>
+        </ol>
+      <li><a href="#events">Player Events</a>
+        <ol>
+          <li><a href="#high-events">High level events</a></li>
+          <li><a href="#low-events">Low level events</a></li>
+        </ol>
+      </li>
+      <li><a href="#sending-messages">Sending messages to components</a></li>
+      <li><a href="#customizing">Customizing ExoPlayer</a>
+        <ol>
+          <li><a href="#custom-guidelines">Custom component guidelines</a></li>
+        </ol>
+      </li>
+      <li><a href="#drm">Digital Rights Management</a></li>
+    </ol>
+    <h2>Key Classes</h2>
+    <ol>
+      <li>{@link android.media.MediaCodec}</li>
+      <li>{@link android.media.MediaExtractor}</li>
+      <li>{@link android.media.AudioTrack}</li>
+    </ol>
+    <h2>Related Samples</h2>
+    <ol>
+      <li><a class="external-link" href="https://github.com/google/ExoPlayer">
+        ExoPlayer Project</a></li>
+      <li><a class="external-link" href="http://google.github.io/ExoPlayer/doc/reference/packages.html">
+        Class Reference</a></li>
+    </ol>
+  </div>
+</div>
+
+
+<p>Playing videos and music is a popular activity on Android devices. The Android framework
+  provides {@link android.media.MediaPlayer} as a quick solution for playing media with minimal
+  code, and the {@link android.media.MediaCodec} and {@link android.media.MediaExtractor} classes
+  are provided for building custom media players. The open source project, ExoPlayer, is a
+  solution between these two options, providing a pre-built player that you can extend.</p>
+
+<p>ExoPlayer supports features not currently provided by
+  {@link android.media.MediaPlayer}, including Dynamic adaptive streaming
+  over HTTP (DASH), SmoothStreaming, and persistent caching. ExoPlayer can be extended
+  to handle additional media formats, and because you include it as part of your app code,
+  you can update it along with your app.</p>
+
+<p>This guide describes how to use ExoPlayer for playing Android supported media formats, as well as
+  DASH and SmoothStreaming playback. This guide also discusses ExoPlayer events, messages, DRM
+  support and guidelines for customizing the player.</p>
+
+<p class="note">
+  <strong>Note:</strong> ExoPlayer is an open source project that is not part of the Android
+  framework and is distributed separately from the Android SDK. The project contains a library and
+  a demo app that shows both simple and more advanced use of ExoPlayer:</p>
+
+<ul>
+    <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/library">
+      ExoPlayer Library</a> &mdash; This part of the project contains the core library classes.</li>
+    <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/demo/src/main/java/com/google/android/exoplayer/demo/simple">
+      Simple Demo</a> &mdash; This part of the app demonstrates a basic use of ExoPlayer.</li>
+    <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/demo/src/main/java/com/google/android/exoplayer/demo/full">
+      Full Demo</a> &mdash; This part of the app demonstrates more advanced features,
+      including the ability to select between multiple audio tracks, a background audio mode,
+      event logging and DRM protected playback. </li>
+</ul>
+
+
+<h2 id="overview">Overview</h2>
+
+<p>ExoPlayer is a media player built on top of the {@link android.media.MediaExtractor} and
+  {@link android.media.MediaCodec} APIs released in Android 4.1 (API level 16). At the core of this
+  library is the {@code ExoPlayer} class. This class maintains the player’s global state, but makes few
+  assumptions about the nature of the media being played, such as how the media data is obtained,
+  how it is buffered or its format. You inject this functionality through ExoPlayer’s {@code
+  prepare()} method in the form of {@code TrackRenderer} objects.</p>
+
+<p>ExoPlayer provides default {@code TrackRenderer} implementations for audio and
+  video, which make use of the {@link android.media.MediaCodec} and {@link android.media.AudioTrack}
+  classes in the Android framework. Both renderers require a {@code SampleSource} object, from which
+  they obtain individual media samples for playback. Figure 1 shows the high level object model for
+  an ExoPlayer implementation configured to play audio and video using these components.</p>
+
+<img src="{@docRoot}images/exoplayer/object-model.png" alt="" id="figure1" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> High level object model for an ExoPlayer configured to play audio
+  and video using {@code TrackRenderer} objects
+</p>
+
+
+<h2 id="trackrenderer">TrackRenderer</h2>
+
+<p>A {@code TrackRenderer} processes a component of media for playback, such as
+  video, audio or text. The ExoPlayer class invokes methods on its {@code TrackRenderer} instances from a
+  single playback thread, and by doing so causes each media component to be rendered as the global
+  playback position is advanced. The ExoPlayer library provides {@code MediaCodecVideoTrackRenderer} as
+  the default implementations rendering video and {@code MediaCodecAudioTrackRenderer} for audio.
+  Both implementations make use of {@link android.media.MediaCodec} to decode individual media
+  samples. They can handle all audio and video formats supported by a given Android device
+  (see <a href="http://developer.android.com/guide/appendix/media-formats.html">Supported Media
+  Formats</a> for details). The ExoPlayer library also provides an implementation for rendering
+  text called {@code TextTrackRenderer}.
+</p>
+
+<p>The code example below outlines the main steps required to instantiate an ExoPlayer to play video
+  and audio using the standard {@code TrackRenderer} implementations.</p>
+
+<pre>
+// 1. Instantiate the player.
+player = ExoPlayer.Factory.newInstance(RENDERER_COUNT);
+// 2. Construct renderers.
+MediaCodecVideoTrackRenderer videoRenderer = …
+MediaCodecAudioTrackRenderer audioRenderer = ...
+// 3. Inject the renderers through prepare.
+player.prepare(videoRenderer, audioRenderer);
+// 4. Pass the surface to the video renderer.
+player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE,
+        surface);
+// 5. Start playback.
+player.setPlayWhenReady(true);
+...
+player.release(); // Don’t forget to release when done!
+</pre>
+
+<p>For a complete example, see the {@code SimplePlayerActivity} in the ExoPlayer demo app, which
+  correctly manages an ExoPlayer instance with respect to both the {@link android.app.Activity} and
+  {@link android.view.Surface} lifecycles.</p>
+
+
+<h2 id="samplesource">SampleSource</h2>
+
+<p>A standard {@code TrackRenderer} implementation requires a {@code SampleSource} to
+  be provided in its constructor. A {@code SampleSource} object provides format information and
+  media samples to be rendered. The ExoPlayer library provides {@code FrameworkSampleSource} and
+  {@code ChunkSampleSource}. The {@code FrameworkSampleSource} class uses {@link
+  android.media.MediaExtractor} to request, buffer and extract the media samples. The {@code
+  ChunkSampleSource} class provides adaptive playback using DASH or SmoothStreaming, and
+  implements networking, buffering and media extraction within the ExoPlayer library.</p>
+
+
+<h3 id="mediaextractor">Providing media using MediaExtractor</h3>
+
+<p>
+  In order to render media formats supported by the Android framework, the {@code
+  FrameworkSampleSource} class uses {@link android.media.MediaExtractor} for networking,
+  buffering and sample extraction functionality. By doing so, it supports any media container format
+  supported by the version of Android where it is running. For more information about media formats
+  supported by Android, see <a href="{@docRoot}guide/appendix/media-formats.html">Supported
+  Media Formats</a>.
+</p>
+
+<p>The diagram in Figure 2 shows the object model for an ExoPlayer implementation using
+  {@code FrameworkSampleSource}.</p>
+
+<img src="{@docRoot}images/exoplayer/frameworksamplesource.png" alt="" id="figure2" />
+<p class="img-caption">
+  <strong>Figure 2.</strong> Object model for an implementation of ExoPlayer that renders
+  media formats supported by Android using {@code FrameworkSampleSource}
+</p>
+
+<p>The following code example outlines how the video and audio renderers are constructed to
+  load the video from a specified URI.</p>
+
+<pre>
+FrameworkSampleSource sampleSource = new FrameworkSampleSource(
+        activity, uri, null, 2);
+MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(
+        sampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0,
+        mainHandler, playerActivity, 50);
+MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
+        sampleSource, null, true);
+</pre>
+
+<p>The ExoPlayer demo app provides a complete implementation of this code in
+  {@code DefaultRendererBuilder}. The {@code SimplePlaybackActivity} class uses it to play one
+  of the videos available in the demo app. Note that in the example, video and audio
+  are muxed, meaning they are streamed together from a single URI. The {@code FrameworkSampleSource}
+  instance provides video samples to the {@code videoRenderer} object and audio samples to the
+  {@code audioRenderer} object as they are extracted from the media container format. It is also
+  possible to play demuxed media, where video and audio are streamed separately from different URIs.
+  This functionality can be achieved by having two {@code FrameworkSampleSource} instances instead
+  of one.</p>
+
+
+<h3 id="adaptive-playback">Providing media for adaptive playback</h3>
+
+<p>ExoPlayer supports adaptive streaming, which allows the quality of the
+  media data to be adjusted during playback based on the network conditions. DASH
+  and SmoothStreaming are examples of adaptive streaming technologies. Both these approaches
+  load media in small chunks (typically 2 to 10 seconds in duration). Whenever a chunk of media
+  is requested, the client selects from a number of possible formats. For example, a client may
+  select a high quality format if network conditions are good, or a low quality format if network
+  conditions are bad. In both techniques, video and audio are streamed separately.</p>
+
+<p>ExoPlayer supports adaptive playback through use of the {@code ChunkSampleSource} class,
+  which loads chunks of media data from which individual samples can be extracted. Each {@code
+  ChunkSampleSource} requires a {@code ChunkSource} object to be injected through its constructor,
+  which is responsible for providing media chunks from which to load and read samples. The {@code
+  DashMp4ChunkSource} and {@code SmoothStreamingChunkSource} classes provide DASH and SmoothStreaming
+  playback using the FMP4 container format. The {@code DashWebMChunkSource} class uses the WebM
+  container format to provide DASH playback.</p>
+
+<p>All of the standard {@code ChunkSource} implementations require a {@code FormatEvaluator} and
+  a {@code DataSource} to be injected through their constructors. The {@code FormatEvaluator}
+  objects select from the available formats before each chunk is loaded. The {@code DataSource}
+  objects are responsible for actually loading the data. Finally, the {@code ChunkSampleSources}
+  require a {@code LoadControl} object that controls the chunk buffering policy.</p>
+
+<p>The object model of an ExoPlayer configured for a DASH adaptive playback is shown in the
+  diagram below. This example uses an {@code HttpDataSource} object to stream the media over the
+  network. The video quality is varied at runtime using the adaptive implementation of {@code
+  FormatEvaluator}, while audio is played at a fixed quality level.</p>
+
+<img src="{@docRoot}images/exoplayer/adaptive-streaming.png" alt="" id="figure3" />
+<p class="img-caption">
+  <strong>Figure 3.</strong> Object model for a DASH adaptive playback using ExoPlayer
+</p>
+
+<p>The following code example outlines how the video and audio renderers are constructed.</p>
+
+<pre>
+Handler mainHandler = playerActivity.getMainHandler();
+LoadControl loadControl = new DefaultLoadControl(
+        new BufferPool(BUFFER_SEGMENT_SIZE));
+BandwidthMeter bandwidthMeter = new BandwidthMeter();
+
+// Build the video renderer.
+DataSource videoDataSource = new HttpDataSource(userAgent,
+        HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter);
+ChunkSource videoChunkSource = new DashMp4ChunkSource(videoDataSource,
+        new AdaptiveEvaluator(bandwidthMeter), videoRepresentations);
+ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource,
+        loadControl, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
+MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(
+        videoSampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT,
+        0, mainHandler, playerActivity, 50);
+
+// Build the audio renderer.
+DataSource audioDataSource = new HttpDataSource(userAgent,
+        HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter);
+ChunkSource audioChunkSource = new DashMp4ChunkSource(audioDataSource,
+        new FormatEvaluator.FixedEvaluator(), audioRepresentation);
+SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource,
+        loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
+MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
+        audioSampleSource, null, true);
+</pre>
+
+<p>In this code, {@code videoRepresentations} and {@code audioRepresentation} are {@code
+  Representation} objects, each of which describes one of the available media streams. In the DASH
+  model, these streams are parsed from a media presentation description (MPD) file. The ExoPlayer
+  library provides a {@code MediaPresentationDescriptionParser} class to obtain {@code
+  Representation} objects from MPD files.</p>
+
+<p class="note">
+  <strong>Note:</strong> Building Representation objects from MPD files is not required. You can
+  build Representation objects from other data sources if necessary.
+</p>
+
+<p>The ExoPlayer demo app provides complete implementation of this code in
+  {@code DashVodRendererBuilder}. The {@code SimplePlaybackActivity} class uses this builder to
+  construct renderers for playing DASH sample videos in the demo app. It asynchronously fetches a
+  specified MPD file in order to construct the required {@code Representation} objects. For an
+  equivalent SmoothStreaming example, see the {@code SmoothStreamingRendererBuilder} class in the
+  demo app.</p>
+
+
+<h4 id="format-selection">Format selection for adaptive playback</h4>
+
+<p>For DASH and SmoothStreaming playback, consider both static format selection at the
+  start of playback and dynamic format selection during playback. Static format selection should be
+  used to filter out formats that should not be used throughout the playback, for example formats
+  with resolutions higher than the maximum supported by the playback device. Dynamic selection varies
+  the selected format during playback, typically to adapt video quality in response to changes in
+  network conditions.</p>
+
+<h5 id="static-selection">Static format selection</h5>
+
+<p>When preparing a player, you should consider filtering out some of the available formats if
+  they are not useable for playback. Static format selection allows you to filter out
+  formats that cannot be used on a particular device or are not compatible with your player.
+  For audio playback, this often means picking a single format to play and discarding the others.</p>
+
+<p>For video playback, filtering formats can be more complicated. Apps should first
+  eliminate any streams that whose resolution is too high to be played by the device. For H.264,
+  which is normally used for DASH and SmoothStreaming playback, ExoPlayer’s {@code MediaCodecUtil}
+  class provides a {@code maxH264DecodableFrameSize()} method that can be used to determine what
+  resolution streams the device is able to handle, as shown in the following code example:</p>
+
+<pre>
+int maxDecodableFrameSize = MediaCodecUtil.maxH264DecodableFrameSize();
+Format format = representation.format;
+if (format.width * format.height &lt;= maxDecodableFrameSize) {
+  // The device can play this stream.
+  videoRepresentations.add(representation);
+} else {
+  // The device isn't capable of playing this stream.
+}
+</pre>
+
+<p>This approach is used to filter {@code Representations} in the {@code DashVodRendererBuilder}
+  class of the ExoPlayer demo app, and similarly to filter track indices in {@code
+  SmoothStreamingRendererBuilder}.</p>
+
+<p>In addition to eliminating unsupported formats, it should be noted that the ability to
+  seamlessly switch between H.264 streams of different resolution is an optional decoder feature
+  available in Android 4.3 (API level 16) and higher, and so is not supported by all devices. The
+  availability of an adaptive H.264 decoder can be queried using {@code MediaCodecUtil}, as shown in
+  the following code example:</p>
+
+<pre>
+boolean isAdaptive = MediaCodecUtil.getDecoderInfo(MimeTypes.VIDEO_H264).adaptive;
+</pre>
+
+<p>The {@code MediaCodecVideoTrackRenderer} class is still able to handle resolution changes on
+  devices that do not have adaptive decoders, however the switch is not seamless. Typically, the
+  switch creates a small discontinuity in visual output lasting around 50-100ms. For devices that
+  do not provide an adaptive decoder, app developers may choose to adapt between formats at
+  a single fixed resolution so as to avoid discontinuities. The ExoPlayer demo app
+  implementation does not pick a fixed resolution.</p>
+
+
+<h5 id="dynamic-selection">Dynamic format selection</h5>
+
+<p>During playback, you can use a {@code FormatEvaluator} to dynamically select from the
+  available video formats. The ExoPlayer library provides a {@code FormatEvaluator.Adaptive}
+  implementation for dynamically selecting between video formats based on the current network
+  conditions.</p>
+
+<p>This class provides a simple, general purpose reference implementation, however you are
+  encouraged to write your own {@code FormatEvaluator} implementation to best suit your particular
+  needs.</p>
+
+
+<h2 id="events">Player Events</h2>
+
+<p>During playback, your app can listen for events generated by the ExoPlayer that indicate the
+  overall state of the player. These events are useful as triggers for updating the app user
+  interface such as playback controls. Many ExoPlayer components also report their own component
+  specific low level events, which can be useful for performance monitoring.</p>
+
+
+<h3 id="high-events">High level events</h3>
+
+<p>ExoPlayer allows instances of {@code ExoPlayer.Listener} to be added and removed using its
+  {@code addListener()} and {@code removeListener()} methods. Registered listeners are notified of
+  changes in playback state, as well as when errors occur that cause playback to fail. For more
+  information about the valid playback states and the possible transitions between them, see the
+  ExoPlayer source code.</p>
+
+<p>Developers who implement custom playback controls should register a listener and use it to
+  update their controls as the player’s state changes. An app should also show an
+  appropriate error to the user if playback fails.</p>
+
+<h3 id="low-events">Low level events</h3>
+
+<p>In addition to high level listeners, many of the individual components provided by the
+  ExoPlayer library allow their own event listeners. For example, {@code
+  MediaCodecVideoTrackRenderer} has constructors that take a {@code
+  MediaCodecVideoTrackRenderer.EventListener}. In the ExoPlayer demo app, {@code SimplePlayerActivity}
+  acts as a listener so that it can adjust the dimensions of the target surface to have the correct
+  height and width ratio for the video being played:</p>
+
+<pre>
+&#64;Override
+public void onVideoSizeChanged(int width, int height) {
+  surfaceView.setVideoWidthHeightRatio(height == 0 ? 1 : (float) width / height);
+}
+</pre>
+
+<p>The {@code RendererBuilder} classes in the ExoPlayer demo app inject the activity as the
+  listener, for example in the {@code DashVodRendererBuilder} class:</p>
+
+<pre>
+MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(
+        videoSampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT,
+        0, <strong>mainHandler, playerActivity</strong>, 50);
+</pre>
+
+<p>Note that you must pass a {@link android.os.Handler} object to the renderer, which determines
+  the thread on which the listener’s methods are invoked. In most cases, you should use a
+  {@link android.os.Handler} associated with the app’s main thread, as is the case in this example.
+  </p>
+
+<p>Listening to individual components can be useful for adjusting UI based on player events, as
+  in the example above. Listening to component events can also be helpful for logging performance
+  metrics. For example, {@code MediaCodecVideoTrackRenderer} notifies its listener of dropped video
+  frames. A developer may wish to log such metrics to track playback performance in their
+  app.</p>
+
+<p>Many components also notify their listeners when errors occur. Such errors may or may not
+  cause playback to fail. If an error does not cause playback to fail, it may still result in
+  degraded performance, and so you may wish to log all errors in order to track playback
+  performance. Note that an ExoPlayer instance always notifies its high level listeners of errors that
+  cause playback to fail, in addition to the listener of the individual component from which the error
+  originated. Hence, you should display error messages to users only from high level listeners.
+  Within individual component listeners, you should use error notifications only for informational
+  purposes.</p>
+
+
+<h2 id="sending-messages">Sending messages to components</h2>
+
+<p>Some ExoPlayer components allow changes in configuration during playback. By convention, you make
+  these changes by passing asynchronous messages through the ExoPlayer to the component.
+  This approach ensures both thread safety and that the configuration change is
+  executed in order with any other operations being performed on the player.</p>
+
+<p>The most common use of messaging is passing a target surface to
+  {@code MediaCodecVideoTrackRenderer}:</p>
+
+<pre>
+player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE,
+        surface);
+</pre>
+
+<p>Note that if the surface needs to be cleared because
+  {@link android.view.SurfaceHolder.Callback#surfaceDestroyed
+  SurfaceHolder.Callback.surfaceDestroyed()} has been invoked, then you must send this
+  message using the blocking variant of {@code sendMessage()}:</p>
+<p>
+
+<pre>
+player.blockingSendMessage(videoRenderer,
+        MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, null);
+</pre>
+
+<p>You must use a blocking message because the contract of {@link
+  android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed()} requires that the
+  app does not attempt to access the surface after the method returns. The {@code
+  SimplePlayerActivity} class in the demo app demonstrates how the surface should be set and
+  cleared.</p>
+
+
+<h2 id="customizing">Customizing ExoPlayer</h2>
+
+<p>One of the main benefits of ExoPlayer over {@link android.media.MediaPlayer} is the ability to
+  customize and extend the player to better suit the developer’s use case. The ExoPlayer library
+  is designed specifically with this in mind, defining a number of abstract base classes and
+  interfaces that make it possible for app developers to easily replace the default implementations
+  provided by the library. Here are some use cases for building custom components:</p>
+
+<ul>
+  <li><strong>{@code TrackRenderer}</strong> - You may want to implement a custom
+    {@code TrackRenderer} to handle media types other than audio and video. The {@code
+    TextTrackRenderer} class within the ExoPlayer library is an example of how to implement a
+    custom renderer. You could use the approach it demonstrates to render custom
+    overlays or annotations. Implementing this kind of functionality as a {@code TrackRenderer}
+    makes it easy to keep the overlays or annotations in sync with the other media being played.</li>
+  <li><strong>{@code SampleSource}</strong> - If you need to support a container format not
+    already handled by {@link android.media.MediaExtractor} or ExoPlayer, consider implementing a
+    custom {@code SampleSource} class.</li>
+  <li><strong>{@code FormatEvaluator}</strong> - The ExoPlayer library provides {@code
+    FormatEvaluator.Adaptive} as a simple reference implementation that switches between different
+    quality video formats based on the available bandwidth. App developers are encouraged to
+    develop their own adaptive {@code FormatEvaluator} implementations, which can be designed to
+    suit their use specific needs.</li>
+  <li><strong>{@code DataSource}</strong> - ExoPlayer’s upstream package already contains a
+    number of {@code DataSource} implementations for different use cases, such as writing and
+    reading to and from a persistent media cache. You may want to implement you own
+    {@code DataSource} class to load data in another way, such as a custom
+    protocol or HTTP stack for data input.</li>
+</ul>
+
+
+<h3 id="custom-guidelines">Custom component guidelines</h3>
+
+<p>If a custom component needs to report events back to the app, we recommend that you
+  do so using the same model as existing ExoPlayer components, where an event listener is passed
+  together with a {@link android.os.Handler} to the constructor of the component.</p>
+
+<p>We recommended that custom components use the same model as existing ExoPlayer components to
+  allow reconfiguration by the app during playback, as described in
+  <a href="#sending-messages">Sending messages to components</a>.
+  To do this, you should implement a {@code ExoPlayerComponent} and receive
+  configuration changes in its {@code handleMessage()} method. Your app should pass
+  configuration changes by calling ExoPlayer’s {@code sendMessage()} and {@code
+  blockingSendMessage()} methods.</p>
+
+
+<h2 id="drm">Digital Rights Management</h2>
+
+<p>On Android 4.3 (API level 18) and higher, ExoPlayer supports Digital Rights Managment (DRM)
+  protected playback. In order to play DRM protected content with ExoPlayer, your app must
+  inject a {@code DrmSessionManager} into the {@code MediaCodecVideoTrackRenderer} and {@code
+  MediaCodecAudioTrackRenderer} constructors. A {@code DrmSessionManager} object is responsible for
+  providing the {@code MediaCrypto} object required for decryption, as well as ensuring that the
+  required decryption keys are available to the underlying DRM module being used.</p>
+
+<p>The ExoPlayer library provides a default implementation of {@code DrmSessionManager}, called
+  {@code StreamingDrmSessionManager}, which uses {@link android.media.MediaDrm}. The session
+  manager supports any DRM scheme for which a modular DRM component exists on the device. All
+  Android devices are required to support Widevine modular DRM (with L3 security, although many
+  devices also support L1). Some devices may support additional schemes such as PlayReady.</p>
+
+<p>The {@code StreamingDrmSessionManager} class requires a {@code MediaDrmCallback} to be
+  injected into its constructor, which is responsible for actually making provisioning and key
+  requests. You should implement this interface to make network requests to your license
+  server and obtain the required keys. The {@code WidevineTestMediaDrmCallback} class in the
+  ExoPlayer demo app sends requests to a Widevine test server.</p>
diff --git a/docs/html/images/exoplayer/adaptive-streaming.png b/docs/html/images/exoplayer/adaptive-streaming.png
new file mode 100644
index 0000000..9fc650c9
--- /dev/null
+++ b/docs/html/images/exoplayer/adaptive-streaming.png
Binary files differ
diff --git a/docs/html/images/exoplayer/frameworksamplesource.png b/docs/html/images/exoplayer/frameworksamplesource.png
new file mode 100644
index 0000000..fd1e314
--- /dev/null
+++ b/docs/html/images/exoplayer/frameworksamplesource.png
Binary files differ
diff --git a/docs/html/images/exoplayer/object-model.png b/docs/html/images/exoplayer/object-model.png
new file mode 100644
index 0000000..e0d6e55
--- /dev/null
+++ b/docs/html/images/exoplayer/object-model.png
Binary files differ
diff --git a/docs/html/images/gpfe-start-0.jpg b/docs/html/images/gpfe-start-0.jpg
index e97381d..bb68aaa 100644
--- a/docs/html/images/gpfe-start-0.jpg
+++ b/docs/html/images/gpfe-start-0.jpg
Binary files differ
diff --git a/docs/html/images/home/auto.png b/docs/html/images/home/auto.png
new file mode 100644
index 0000000..233d69d
--- /dev/null
+++ b/docs/html/images/home/auto.png
Binary files differ
diff --git a/docs/html/images/home/tv.png b/docs/html/images/home/tv.png
new file mode 100644
index 0000000..47bf4b0
--- /dev/null
+++ b/docs/html/images/home/tv.png
Binary files differ
diff --git a/docs/html/images/home/wear.png b/docs/html/images/home/wear.png
new file mode 100644
index 0000000..c7a2045
--- /dev/null
+++ b/docs/html/images/home/wear.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index de2980b..c2bf6b6 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -11,13 +11,31 @@
   <div class="fullscreen-carousel-content">
     <div class="vcenter">
       <div class="wrap clearfix">
-        <div class="resource-widget resource-flow-layout wrap col-16"
+
+        <div class="static resource-flow-layout wrap col-16">
+          <div class="resource resource-card resource-card-18x6">
+            <div class="card-bg" style="background-image: url('/preview/images/l-dev-prev.png');"></div>
+            <div class="card-info">
+              <div class="section"></div>
+              <div class="title">Android L Developer Preview</div>
+              <div class="description ellipsis" style="height: 285px;">
+                <div class="text" style="height: auto;">
+                  <p style="font-size:16px;">Get an early look at the next Android release and
+                    start using new APIs so your apps are ready when the platform officially launches.</p>
+                  <p>
+                  <a href="{@docRoot}preview/index.html" class="landing-button landing-secondary">Learn more</a></p>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+
+        <div class="resource-widget resource-flow-layout wrap col-16 no-section"
           data-query="collection:index/primary"
           data-resourceStyle="card"
           data-sortOrder="-timestamp"
-          data-numStacks="3"
-          data-maxResults="4"
-          data-cardSizes="18x6,6x2,6x2,6x2">
+          data-maxResults="3"
+          data-cardSizes="6x2,6x2,6x2">
         </div> <!-- end .resource-widget -->
       </div> <!-- end .wrap -->
     </div> <!-- end .vcenter -->
@@ -38,57 +56,26 @@
 
 
 <div class="landing-rest-of-page">
-  <div class="landing-section" style="background-color:#f5f5f5">
+  <div class="landing-section">
     <div class="wrap">
       <div class="landing-section-header">
-        <div class="landing-h1">Android, Everywhere You Need It</div>
-        <div class="landing-subhead">
-          Android runs on hundreds of millions of handheld devices around the world, <br /> and it now supports these exciting, new form-factors.
+        <div class="landing-h1">Develop for Multiple Form Factors</div>
+        <div class="landing-subhead" style="margin-top: 20px;">
+          Android runs on hundreds of millions of handheld devices around the world, <br />
+          and it now supports these exciting, new form-factors.
         </div>
       </div>
-      <div class="landing-body">
+      <div class="landing-body" style="margin-top: 80px;">
         <div class="landing-breakout cols">
-
-         <!-- <div class="resource-widget resource-flow-layout col-16" data-query="collection:index/devices"
-          data-sortorder="" data-cardsizes="6x6, 6x6, 6x6" data-maxresults="3"></div>-->
-
           <div class="col-3-wide">
-            <img src="" alt="">
-
-            <p>Wear</p>
-            <p class="landing-small">
-              Provide information on-the-go for your users, whenever they need it.
-            </p>
-            <p class="landing-small">
-              <a href="{@docRoot}wear">Learn about Android Wear</a>
-            </p>
+              <a href="{@docRoot}wear/index.html"><img src="{@docRoot}images/home/wear.png"></a>
           </div>
-
-          <div class="col-3-wide">
-            <img src="" alt="">
-
-            <p>TV</p>
-            <p class="landing-small">
-              Build your apps for the big screen and bring your content to life.
-            </p>
-            <p class="landing-small">
-              <a href="{@docRoot}tv">Learn about Android TV</a>
-            </p>
+          <div class="col-3-wide">            
+              <a href="{@docRoot}tv/index.html"><img src="{@docRoot}images/home/tv.png"></a>
           </div>
-
-          <div class="col-3-wide">
-            <img src="" alt="">
-
-            <p>Auto</p>
-            <p class="landing-small">
-              Extend your music apps to automobile
-              entertainment systems.
-            </p>
-            <p class="landing-small">
-              <a href="{@docRoot}auto">Learn about Android Auto</a>
-            </p>
+          <div class="col-3-wide">            
+              <a href="{@docRoot}auto/index.html"><img src="{@docRoot}images/home/auto.png"></a>
           </div>
-
         </div>
       </div>
     </div>  <!-- end .wrap -->
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index ca19c02..a92236e 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -2,10 +2,9 @@
   "index/primary": {
     "title": "",
     "resources": [
-      "preview/index.html",
-      "preview/material/index.html",
-      "preview/material/index.html",
-      "preview/material/index.html" 
+      "distribute/essentials/quality/tablets.html",
+      "distribute/engage/game-services.html",
+      "distribute/googleplay/edu/about.html" 
     ]
   },
   "index/devices": {
@@ -46,14 +45,14 @@
     "resources": [
       "distribute/googleplay/edu/about.html",
       "distribute/googleplay/edu/start.html",
-      "distribute/googleplay/edu/faq.html"
+      "https://developers.google.com/edu/faq"
     ]
   },
   "distribute/essentials": {
     "resources": [
       "distribute/essentials/quality/core.html",
       "distribute/essentials/quality/tablets.html",
-      "distribute/essentials/gpfe-guidelines.html",
+      "https://developers.google.com/edu/guidelines",
       "distribute/essentials/optimizing-your-app.html",
       "distribute/essentials/best-practices/apps.html",
       "distribute/essentials/best-practices/games.html"
@@ -166,16 +165,18 @@
     "title": "About Google Play for Education / Developers",
     "resources": [
       "distribute/googleplay/edu/start.html",
-      "distribute/essentials/gpfe-guidelines.html",
-      "distribute/googleplay/edu/faq.html",
-      "distribute/essentials/quality/tablets.html"
+      "https://developers.google.com/edu/guidelines",
+      "https://developers.google.com/edu/faq",
+      "distribute/essentials/quality/tablets.html",
+      "https://developers.google.com/edu/",
+      "https://www.google.com/edu/tablets/#tablets-family"
     ]
   },
   "distribute/googleplay/gpfe/dev": {
     "title": "About Google Play for Education / Developers",
     "resources": [
       "distribute/googleplay/edu/about.html",
-      "distribute/essentials/gpfe-guidelines.html",
+      "https://developers.google.com/edu/guidelines",
       "distribute/essentials/quality/tablets.html",
       "distribute/googleplay/developer-console.html",
       "http://play.google.com/about/developer-distribution-agreement-addendum.html",
@@ -207,7 +208,7 @@
     "resources": [
       "distribute/googleplay/developer-console.html",
       "distribute/googleplay/edu/start.html",
-      "distribute/googleplay/edu/faq.html"
+      "https://developers.google.com/edu/faq"
     ]
   },
   "distribute/essentials/eduessentials/educators": {
@@ -587,7 +588,7 @@
     "resources": [
       "distribute/essentials/quality/core.html",
       "distribute/essentials/quality/tablets.html",
-      "distribute/essentials/gpfe-guidelines.html"
+      "https://developers.google.com/edu/guidelines"
     ]
   },
   "distribute/toolsreference/launchchecklist/rating": {
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
index 2f63700..eb7bfb6 100644
--- a/docs/html/jd_extras.js
+++ b/docs/html/jd_extras.js
@@ -219,7 +219,7 @@
     "keywords": [],
     "type": "support",
     "titleFriendly": ""
-  },   
+  },
   {
     "lang": "en",
     "group": "",
@@ -582,7 +582,7 @@
     "image":"http://chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
     "lang":"en",
     "type":"about"
-  }, 
+  },
   {
     "lang": "en",
     "group": "",
@@ -711,7 +711,7 @@
     "timestamp": 1383243492000,
     "image": "http://i1.ytimg.com/vi/vzvpcEffvaE/maxresdefault.jpg",
     "title": "Introducing Google Play for Education",
-    "summary": "Google Play for Education is a destination where schools can find great, teacher-approved, educational apps and videos on Play Store. Teachers can filter content by subject matter, grade and other criteria. Bulk purchase and instant distribution let educators bring your apps directly to classrooms and schools.",
+    "summary": "Google Play for Education is a destination where schools can find great, teacher-approved, educational content&mdash;from videos and books, to educational apps&mdash;all in one place. Teachers can filter content by subject matter, grade and other criteria. Bulk purchase and instant distribution let educators bring your apps directly to classrooms and schools.",
     "keywords": [],
     "type": "youtube",
     "titleFriendly": ""
@@ -1139,5 +1139,57 @@
     "keywords": ["analytics, user behavior"],
     "type": "sdk",
     "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/edu/guidelines",
+    "timestamp": null,
+    "image": "http://developer.android.com/distribute/images/edu-guidelines.jpg",
+    "title": "Education Guidelines",
+    "summary": "These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.",
+    "keywords": [],
+    "type": "",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/edu/faq",
+    "timestamp": null,
+    "image": "http://developer.android.com/distribute/images/gpfe-faq.jpg",
+    "title": "Education FAQ",
+    "summary": "Answers to common questions you might have about Google Play for Education.",
+    "keywords": [],
+    "type": "",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/edu/",
+    "timestamp": null,
+    "image": "https://developers.google.com/edu/images/edu-guidelines.jpg",
+    "title": "Chrome Apps in Google Play for Education",
+    "summary": "Find out more about Chrome apps in Google Play for Education.",
+    "keywords": [],
+    "type": "",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://www.google.com/edu/tablets/#tablets-family",
+    "timestamp": null,
+    "image": "https://www.google.com/edu/images/tablets/big-tablet.png",
+    "title": "Google Play for Education Tablets",
+    "summary": "Google Play for Education leverages a diverse set up tablets approved for the classroom which may help inform you how to build educational apps.",
+    "keywords": [],
+    "type": "",
+    "titleFriendly": ""
   }
-]); 
\ No newline at end of file
+]);
\ No newline at end of file
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index 8ec2470..d9cac48 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -1,4 +1,4 @@
-page.title=L Developer Preview APIs
+page.title=API Overview
 excludeFromSuggestions=true
 sdk.platform.apiLevel=20
 @jd:body
@@ -18,7 +18,7 @@
       <li><a href="#ART">New Android Runtime (ART)</a></li>
       <li><a href="#BehaviorNotifications">If your app implements notifications...</a></li>
       <li><a href="#BehaviorMediaControl">If your app uses RemoteControlClient...</a></li>
-      <li><a href="#BehaviorGetRecentTasks">If your app uses ActivityManager.getRecentTasks()...</a></li>
+<li><a href="#BehaviorGetRecentTasks">If your app uses ActivityManager.getRecentTasks()...</a></li>
     </ol>
   </li>
   <li><a href="#UI">User Interface</a>
@@ -69,7 +69,7 @@
   <li><a href="#Enterprise">Enterprise</a>
     <ol>
       <li><a href="#ManagedProvisioning">Managed provisioning</a></li>
-      <li><a href="#LockToAppMode">Lock-to-App mode</a></li>
+      <li><a href="#TaskLocking">Task locking</a></li>
     </ol>
   </li>
   <li><a href="#Printing">Printing Framework</a>
@@ -163,10 +163,10 @@
 backgrounds to match the new material design widgets. Make sure that all your
 notifications look right with the new color scheme:</p>
 
-<div class="figure" style="width:220px">
+<div class="figure" style="width:320px">
   <img src="images/hun-example.png"
     srcset="images/hun-example@2x.png 2x"
-    alt="" width="220" height="372" id="figure1" />
+    alt="" width="320" height="541" id="figure1" />
   <p class="img-caption">
     <strong>Figure 1.</strong> Fullscreen activity showing a heads-up notification
   </p>
@@ -177,7 +177,7 @@
   <li>Update or remove assets that involve color.</li>
 
   <li>The system automatically inverts action icons in notifications. Use
-  {@code android.app.Notification.Builder.setColor()} to set an accent color
+  {@code android.app.Notification. Builder.setColor()} to set an accent color
   in a circle behind your {@link android.app.Notification#icon} image.</li>
 
   <li>The system ignores all non-alpha channels in action icons and the main
@@ -188,7 +188,9 @@
 <p>If you are currently adding sounds and vibrations to your notifications by
 using the {@link android.media.Ringtone}, {@link android.media.MediaPlayer},
 or {@link android.os.Vibrator} classes, remove this code so that
-the system can present notifications correctly in <a href="#DoNotDisturb">Do Not Disturb</a> mode. Instead, use the {@link android.app.Notification.Builder} methods instead to add sounds and vibration.</p>
+the system can present notifications correctly in <a href="#DoNotDisturb">Do
+Not Disturb</a> mode. Instead, use the {@link android.app.Notification.Builder}
+methods instead to add sounds and vibration.</p>
 
 <p>Notifications now appear in a small floating window
 (also called a <em>heads-up notification</em>) when the device is active
@@ -218,40 +220,46 @@
 providing a consistent experience for users across the lockscreen and
 unlocked device.</p>
 
-<p>The L Developer Preview introduces a new {@code android.app.Notification.MediaStyle} template which is recommended for this purpose. {@code MediaStyle} converts notification actions that you added with {@link android.app.Notification.Builder#addAction(int, java.lang.CharSequence, android.app.PendingIntent) Notification.Builder.addAction()} into compact buttons embedded in your app's media playback notifications.</p>
+<p>The L Developer Preview introduces a new
+{@code android.app.Notification.MediaStyle} template which is recommended for
+this purpose. {@code MediaStyle} converts notification actions that you added
+with
+{@link android.app.Notification.Builder#addAction(int, java.lang.CharSequence,
+  android.app.PendingIntent)
+Notification.Builder.addAction()} into compact buttons embedded in your app's
+media playback notifications.</p>
 
 <p>If you are using the new
-{@code android.media.session.MediaSession} class (see <a href="#MediaPlaybackControl">Media Playback Control</a> below), attach your session
-token with {@code Notification.MediaStyle.setMediaToken()} to inform the
-system that this notification controls an ongoing media session.</p>
+{@code android.media.session.MediaSession} class
+(see <a href="#MediaPlaybackControl">Media Playback Control</a> below), attach
+your session token with {@code Notification.MediaStyle.setMediaToken()} to
+inform the system that this notification controls an ongoing media session.</p>
 
 <p>Call {@code
 Notification.Builder.setVisibility(Notification.VISIBILITY_PUBLIC)} to mark a
-notification as safe to show atop any lockscreen (secure or otherwise). For more information, see
-<a href="#LockscreenNotifications">Lockscreen Notifications</a>.</p>
+notification as safe to show atop any lockscreen (secure or otherwise). For more
+information, see <a href="#LockscreenNotifications">Lockscreen Notifications</a>.</p>
 
 <h3 id="BehaviorGetRecentTasks">If your app uses ActivityManager.getRecentTasks()...</h3>
 
-<p>With the introduction of the new <em>concurrent documents and activities tasks</em> feature in the upcoming
-release (see <a href="#Recents">Concurrent documents and activities in Recents
-screen</a> below),
+<p>With the introduction of the new <em>concurrent documents and activities
+tasks</em> feature in the upcoming release (see <a href="#Recents">Concurrent
+documents and activities in Recents screen</a> below),
 the {@link android.app.ActivityManager#getRecentTasks
-ActivityManager.getRecentTasks()} method is now
-deprecated to improve user privacy. For backward
-compatibility, this method still returns a small subset of its data, including the
-calling application’s own tasks and possibly some other non-sensitive tasks
-(such as Home). If your app is using this method to retrieve its own tasks,
-use {@code android.app.ActivityManager.getAppTasks()} instead to retrieve that
-information.</p>
+ActivityManager.getRecentTasks()} method is now deprecated to improve user
+privacy. For backward compatibility, this method still returns a small subset of
+its data, including the calling application’s own tasks and possibly some other
+non-sensitive tasks (such as Home). If your app is using this method to retrieve
+its own tasks, use {@code android.app.ActivityManager.getAppTasks()} instead to
+retrieve that information.</p>
 
 <h2 id="UI">User Interface</h2>
 
 <h3 id="MaterialDesign">Material design support</h3>
 
 <p>The upcoming release adds support for Android's new <em>material</em> design
-style. You can create
-apps with material design that are visually dynamic and have UI element transitions
-that feel natural to users. This support includes:</p>
+style. You can create apps with material design that are visually dynamic and
+have UI element transitions that feel natural to users. This support includes:</p>
 
 <ul>
 
@@ -268,9 +276,9 @@
 <a href="{@docRoot}preview/material/index.html">Material Design</a>.</p>
 
 <h3 id="LockscreenNotifications">Lockscreen notifications</h3>
-<p>Lockscreens in the L Developer Preview have the ability to present notifications.
-Users can choose via <em>Settings</em> whether to allow sensitive notification
-content to be shown over a secure lockscreen.</p>
+<p>Lockscreens in the L Developer Preview have the ability to present
+notifications. Users can choose via <em>Settings</em> whether to allow
+sensitive notification content to be shown over a secure lockscreen.</p>
 
 <p>Your app can control the level of detail visible when its notifications are
 displayed over the secure lockscreen. To control the visibility level, call
@@ -287,8 +295,12 @@
 
 <p>When {@code VISIBILITY_PRIVATE} is set, you can also provide a redacted
 version of the notification content that hides personal details. For example,
-an SMS app might display a notification that shows "You have 3 new text messages." but hides the message content and senders. To provide this alternative notification, first create the replacement notification using {@link android.app.Notification.Builder}. When you create the private notification object, attach
-the replacement notification to it through the {@code Notification.Builder.setPublicVersion()} method.</p>
+an SMS app might display a notification that shows "You have 3 new text messages."
+but hides the message content and senders. To provide this alternative
+notification, first create the replacement notification using
+{@link android.app.Notification.Builder}. When you create the private
+notification object, attach the replacement notification to it through the
+{@code Notification.Builder.setPublicVersion()} method.</p>
 
 <h3 id="DoNotDisturb">Do Not Disturb mode</h3>
 
@@ -354,7 +366,8 @@
 
 <p>To insert a logical break so that the system treats your activity as a new
 task, use {@code android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT} when
-launching the activity with {@link android.app.Activity#startActivity(android.content.Intent) startActivity()}. You can also get this behavior by declaring the
+launching the activity with {@link android.app.Activity#startActivity(android.content.Intent)
+startActivity()}. You can also get this behavior by declaring the
 <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
 attribute {@code documentLaunchMode="intoExisting"} or {@code ="always"} in your
 manifest.</p>
@@ -381,7 +394,8 @@
 been updated to incorporate 36.0.0.0 as the version number.</p>
 
 <p>Additionally, this release brings support for the
-<a href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html">WebAudio</a>, <a href="https://www.khronos.org/webgl/">WebGL</a>, and
+<a href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html">WebAudio</a>,
+<a href="https://www.khronos.org/webgl/">WebGL</a>, and
 <a href="http://www.webrtc.org/">WebRTC</a> open standards. To learn more about
 the new features included in this release, see <a href="https://developer.chrome.com/multidevice/webview/overview">WebView for Android</a>.</p>
 
@@ -424,8 +438,10 @@
 <li>Backward compatibility with OpenGL ES 2.0 and 3.0
 </ul>
 
-<p>The Java interface for OpenGL ES 3.1 on Android is provided with GLES31. When using OpenGL ES 3.1, be sure that you declare it in your manifest file with the
-<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature&gt;}</a> tag and the {@code android:glEsVversion} attribute. For example:</p>
+<p>The Java interface for OpenGL ES 3.1 on Android is provided with GLES31. When
+using OpenGL ES 3.1, be sure that you declare it in your manifest file with the
+<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature&gt;}</a>
+tag and the {@code android:glEsVversion} attribute. For example:</p>
 
 <pre>
 &lt;manifest&gt;
@@ -434,7 +450,9 @@
 &lt;/manifest&gt;
 </pre>
 
-<p>For more information about using OpenGL ES, including how to check the device’s supported OpenGL ES version at runtime, see the <a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL ES API guide</a>.</p>
+<p>For more information about using OpenGL ES, including how to check the
+device’s supported OpenGL ES version at runtime, see the
+<a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL ES API guide</a>.</p>
 
 <h2 id="Multimedia">Multimedia</h2>
 
@@ -462,12 +480,13 @@
 <ul>
   <li>Your app can now supply audio data in floating-point format
 ({@code android.media.AudioFormat.ENCODING_PCM_FLOAT}). This permits greater
-dynamic range, more consistent precision, and greater headroom. Floating-point arithmetic is especially useful during intermediate calculations. Playback
+dynamic range, more consistent precision, and greater headroom. Floating-point
+arithmetic is especially useful during intermediate calculations. Playback
 end-points use integer format for audio data, and with lower bit-depth. (In the
 L Developer Preview, portions of the internal pipeline are not yet
 floating-point.)
-  <li>Your app can now supply audio data as a {@link java.nio.ByteBuffer}, in the same
-format as provided by {@link android.media.MediaCodec}.
+  <li>Your app can now supply audio data as a {@link java.nio.ByteBuffer}, in
+the same format as provided by {@link android.media.MediaCodec}.
   <li>The {@code WRITE_NON_BLOCKING} option can simplify buffering and
     multithreading for some apps.
 </ul>
@@ -501,33 +520,40 @@
 
 <h3 id="DirectorySelection">Directory selection</h3>
 
-<p>The L Developer Preview extends the <a href="{@docRoot}guide/topics/providers/document-provider.html">Storage Access Framework</a> to let users select an entire directory, rather than individual files, to
-give your app read/write access to media files. When a directory is selected,
-your app also has access to all its child directories and content.</p>
+<p>The L Developer Preview extends the <a href="{@docRoot}guide/topics/providers/document-provider.html">Storage Access Framework</a> to let users select an entire directory subtree,
+giving apps read/write access to all contained documents without requiring user
+confirmation for each item.</p>
 
-<p>To get the absolute paths to directories on external storage devices where
-applications can store media files, call the new
-{@code android.content.Context.getExternalMediaDirs()} method. No
-additional
-permissions are needed by your app to read or write to the returned paths.
-In this context, "external storage devices" are those devices which the system
-considers to be a
-permanent part of the device, and includes emulated external storage and
-physical media slots such as SD cards in battery compartments.</p>
+<p>To select a directory subtree, build and send an
+{@code android.intent.action.OPEN_DOCUMENT_TREE} {@link android.content.Intent}.
+The system displays all
+{@link android.provider.DocumentsProvider} instances that support subtree selection,
+letting the user browse and select a directory. The returned URI represents access to the selected
+subtree. You can then use {@code DocumentsContract.buildChildDocumentsUriUsingTree()}
+and {@code DocumentsContract.buildDocumentUriUsingTree()} along with
+{@code ContentResolver.query()} to explore the subtree.</p>
 
-<p>You can bring up a system UI to allow the user to pick a directory subtree.
-To do so, send  {@code android.intent.action.OPEN_DOCUMENT_TREE} in an
-{@link android.content.Intent}. If the call is successful, the system displays
-the {@link android.provider.DocumentsProvider} instances installed on the
-device for the user to select. When the user selects a directory from this UI,
-the system returns a URI representing the selected directory tree.</p>
+<p>The new {@code DocumentsContract.createDocument()} method lets you create
+new documents or directories anywhere under the subtree. To manage
+existing documents, use {@code DocumentsContract.renameDocument()} and
+{@code DocumentsContract.deleteDocument()}. Check {@code DocumentsContract.Document.COLUMN_FLAGS}
+to verify provider support for these calls before issuing them.</p>
 
-<p>If you want to access a document in an existing directory, call the
-{@code android.provider.DocumentsContract.buildDocumentViaUri()} method.
-Pass the method a URI representing the path to the parent directory, and the
-target document
-ID. The method returns a new {@link android.net.Uri} which your app can
-use to write media content with {@code DocumentsContract.createDocument()}.
+<p>If you're implementing a {@link android.provider.DocumentsProvider} and want
+to support subtree selection, implement {@code DocumentsProvider.isChildDocument()}
+and include {@code Documents.Contract.FLAG_SUPPORTS_IS_CHILD} in your
+{@code Root.COLUMN_FLAGS}.</p>
+
+<p>The L Developer Preview also introduces new package-specific directories on
+shared storage where your app can place media files for inclusion in
+{@link android.provider.MediaStore}. The new
+{@code android.content.Context.getExternalMediaDirs()} returns paths to these
+directories on all shared storage devices. Similarly to
+{@link android.content.Context#getExternalFilesDir(java.lang.String) Context.getExternalFilesDir()},
+no additional permissions are needed by your app to access the returned paths. The
+platform periodically scans for new media in these directories, but you can also
+use {@link android.media.MediaScannerConnection} to explicitly scan for new
+content.</p>
 
 <h2 id="Wireless">Wireless &amp; Connectivity</h2>
 
@@ -561,7 +587,8 @@
 network.</p>
 
 <h3 id="BluetoothBroadcasting">Bluetooth broadcasting</h3>
-<p>Android 4.3 introduced platform support for <a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html">Bluetooth Low Energy</a>
+<p>Android 4.3 introduced platform support for
+  <a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html">Bluetooth Low Energy</a>
 (BLE) in the central role. In the L Developer Preview, an Android device can now
 act as a Bluetooth LE <em>peripheral device</em>. Apps can use this capability
 to make their presence known to
@@ -569,7 +596,8 @@
 function as a pedometer or health monitor and communicate its data with another
 BLE device.</p>
 
-<p>The new {@code android.bluetooth.le} APIs enable your apps to broadcast advertisements, scan for responses, and form connections with nearby BLE devices.
+<p>The new {@code android.bluetooth.le} APIs enable your apps to broadcast
+advertisements, scan for responses, and form connections with nearby BLE devices.
 You must add the {@code android.permission.BLUETOOTH_ADMIN} permission in your
 manifest in order for your app to use the new advertising and scanning features.</a>
 
@@ -692,7 +720,7 @@
 
 <img src="images/battery_historian.png"
      srcset="images/battery_historian@2x.png 2x"
-    alt="" width="440" height="240"
+    alt="" width="760" height="462"
     id="figure2" />
 <p class="img-caption">
   <strong>Figure 2.</strong>HTML visualization generated by the Battery
@@ -726,7 +754,7 @@
 <div class="figure" style="width:360px">
   <img src="images/managed_apps_launcher.png"
     srcset="images/managed_apps_launcher@2x.png 2x"
-    alt="" width="360" height="572" id="figure3" />
+    alt="" width="360" height="609" id="figure3" />
   <p class="img-caption">
     <strong>Figure 3.</strong> Launcher screen showing managed apps (marked with
     a lock badge)
@@ -734,17 +762,10 @@
 </div>
 
 <p>The L Developer Preview provides new functionality for running apps within
-an enterprise environment:</p>
-<ul>
-<li><strong>Create managed user profiles</strong>. A device administrator can
-initiate a managed provisioning process to add a co-present but separate managed
-profile to a device with an existing personal account. The administrator has
-control over the managed profile.</li>
-<li><strong>Set device owner</strong>. Device administrators can also initiate a
-managed provisioning process to automatically provision a
-currently-unprovisioned device such that they have full control over the
-device.</li>
-</ul>
+an enterprise environment. A device administrator can
+initiate a managed provisioning process to add a co-present but separate <em>managed
+profile</em> to a device with an existing personal account. The administrator has
+control over the managed profile.</p>
 
 <p>To start the managed provisioning process, send {@code
 ACTION_PROVISION_MANAGED_PROFILE} in an {@link android.content.Intent}. If the
@@ -767,47 +788,71 @@
 the managed apps visually prominent by appending a “work” badge to the icon
 drawable with {@code android.os.UserManager.getBadgeDrawableForUser()}.</p>
 
-<h3 id="LockToAppMode">Lock-to-App mode</h3>
-<p>The L Developer Preview introduces a new <em>Lock-to-App</em> mode that
+<h3 id="TaskLocking">Task locking</h3>
+<p>The L Developer Preview introduces a new task locking API that
 lets you temporarily restrict users from leaving your app or being interrupted
-by notifications. Once your app activates this mode, users will not be able to
-see notifications, access other apps, or return to the Home screen, until your
+by notifications. This could be used, for example, if you are developing an
+education app to support high stakes assessment requirements on Android.
+Once your app activates this mode, users will not be able to see
+notifications, access other apps, or return to the Home screen, until your
 app exits the mode.</p>
 
-<p>To prevent unauthorized usage, the device on which you want to activate
-this mode must have managed profiles or must be fully controlled by a device administrator (see <a href="#ManagedProvisioning">Managed Provisioning</a> for more information). Furthermore, the device or managed profile owner must
-authorize apps to use this mode by calling {@code android.app.admin.DevicePolicyManager.setLockTaskComponents()}.</p>
+<p>To prevent unauthorized usage, only authorized apps can activate task locking.
+Furthermore, task locking authorization must be granted by a
+specially-configured <em>device owner</em> app, through the {@code android.app.admin.DevicePolicyManager.setLockTaskComponents()} method.</p>
 
-<p>Before activating this mode in your app, verify that your activity is authorized by calling {@code DevicePolicyManager.isLockTaskPermitted()}.</p>
+<p>To set up a device owner, follow these steps:</p>
+<ol>
+<li>Attach a device running an <a href="https://source.android.com/source/building-running.html">Android {@code userdebug} build</a> to your development machine.</li>
+<li>Install your device owner app.</li>
+<li>Create a {@code device_owner.xml} file and save it to the {@code /data/system}
+directory on the device.
+<pre>
+$ adb root
+$ adb shell stop
+$ rm /tmp/device_owner.xml
+$ echo "&lt;?xml version='1.0' encoding='utf-8' standalone='yes' ?&gt;"
+&gt;&gt; /tmp/device_owner.xml
+$ echo "&device-owner package=\"&lt;your_device_owner_package&gt;\"
+name=\"*&lt;your_organization_name&gt;\" /&gt;" &gt;&gt; /tmp/device_owner.xml
+$ adb push /tmp/device_owner.xml /data/system/device_owner.xml
+$ adb reboot
+</pre>
+</li>
+</ol>
 
-<p>To activate <em>Lock-to-App</em> mode, call
+<p>Before using the task locking API in your app, verify that your activity is
+authorized by calling {@code DevicePolicyManager.isLockTaskPermitted()}.</p>
+
+<p>To activate task locking, call
 {@code android.app.Activity.startLockTask()} from your authorized activity.</p>
 
-<p>When <em>Lock-to-App</em> mode is active, the following behavior takes
-effect:</p>
+<p>When task locking is active, the following behavior takes effect:</p>
 
 <ul>
-<li>The status bar is blank, and user notifications and status information is hidden.</li>
-<li>The Home and Recent Apps button is hidden.</li>
+<li>The status bar is blank, and user notifications and status information is
+hidden.</li>
+<li>The Home and Recent Apps buttons are hidden.</li>
 <li>Other apps may not launch new activities.</li>
 <li>The current app may start new activities, as long as doing so does not
 create new tasks.</li>
+<li>The user remains locked on your app until an authorized activity calls
+{@code Activity.stopLockTask()}.</li>
 </ul>
 
-<p>The device will remain in this mode until an authorized activity calls
-{@code Activity.stopLockTask()}.
-
 <h2 id="Printing">Printing Framework</h2>
 
 <h3 id="PDFRender">Render PDF as bitmap</h3>
 <p>You can now render PDF document pages into bitmap images for printing by
 using the new {@code android.graphics.pdf.PdfRenderer} class. You must specify a
-{@link android.os.ParcelFileDescriptor} that is seekable (that is, the content can be randomly
-accessed) on which the system writes the the printable content. Your app can
-obtain a page for rendering with {@code openPage()}, then call {@code render()}
-to turn the opened {@code PdfRenderer.Page} into a bitmap. You can also set
-additional parameters if you only want to convert a portion of the document into
-a bitmap image (for example, to implement <a href="http://en.wikipedia.org/wiki/Tiled_rendering">tiled rendering</a> in order to zoom in on the document).</p>
+{@link android.os.ParcelFileDescriptor} that is seekable (that is, the content
+can be randomly accessed) on which the system writes the the printable content.
+Your app can obtain a page for rendering with {@code openPage()}, then call
+{@code render()} to turn the opened {@code PdfRenderer.Page} into a bitmap. You
+can also set additional parameters if you only want to convert a portion of the
+document into a bitmap image (for example, to implement
+<a href="http://en.wikipedia.org/wiki/Tiled_rendering">tiled rendering</a> in
+order to zoom in on the document).</p>
 
 <h2 id="TestingA11y">Testing &amp; Accessibility </h2>
 
@@ -833,8 +878,7 @@
 can now retrieve detailed information about the properties of windows on the
 screen that sighted users can interact with. To retrieve a list of
 {@code android.view.accessibility.AccessibilityWindowInfo} objects
-representing the
-windows information, call the new
+representing the windows information, call the new
 {@code android.accessibilityservice.AccessibilityService.getWindows()} method.
 <li>You can use the new {@code android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction} to define standard or customized
 actions to perform on an {@link android.view.accessibility.AccessibilityNodeInfo}.
@@ -845,13 +889,16 @@
 <h2 id="Manifest">Manifest Declarations</h2>
 
 <h3 id="ManifestFeatures">Declarable required features</h3>
-<p>The following values are now supported in the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature&gt;}</a> element, so you
-can ensure that your app is installed only on devices that provide the features
+<p>The following values are now supported in the
+<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature&gt;}</a>
+element, so you can ensure that your app is installed only on devices that provide the features
 your app needs.</p>
 
 <ul>
 <li>{@code FEATURE_LEANBACK}. Declares that your app must be installed only on
-devices that support the <a href="{@docRoot}training/tv/index.html}">Android TV</a>user interface. Example:
+devices that support the
+<a href="{@docRoot}training/tv/index.html}">Android TV</a> user interface.
+Example:
 <pre>
 &lt;uses-feature android:name="android.software.leanback"
               android:required="true" /&gt;
@@ -866,7 +913,9 @@
 </ul>
 
 <h3 id="ManifestPermissions">User permissions</h3>
-<p>The following values are now supported in the <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code &lt;uses-permission&gt;}</a> to declare the
+<p>The following values are now supported in the
+<a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code
+  &lt;uses-permission&gt;}</a> to declare the
 permissions your app requires in order to access certain APIs.
 
 <ul>
diff --git a/docs/html/preview/google-play-services-wear.html b/docs/html/preview/google-play-services-wear.html
new file mode 100644
index 0000000..ad8891f
--- /dev/null
+++ b/docs/html/preview/google-play-services-wear.html
@@ -0,0 +1,95 @@
+<html><head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta name="viewport" content="width=device-width">
+
+<meta name="Description" content="Google Play services will fully roll out to the hundreds of millions of Android devices in early July. Because of this, we usually wait to release the Google Play services SDK until all users receive the most updated Google Play services on their devices…">
+<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
+<title>Google Play services Preview for Wear | Android Developers</title>
+
+<!-- STYLESHEETS -->
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
+</head>
+<body>
+<div class="col-12" id="doc-col">
+
+<h1 itemprop="name">Google Play services Preview for Wear</h1>
+      
+    
+  
+
+
+  
+  <div id="jd-content">
+  <div class="jd-descr" itemprop="articleBody">
+<p>The Google Play services app is currently being rolled out to the hundreds of millions of
+Android devices and will complete in early July. Because of this, we usually wait to release the Google Play
+services SDK until all users receive the app. This guarantees that your newly-updated apps can
+run on the most devices as possible.</p>
+
+<p>However, if want to develop for Android Wear now, complete the following steps
+to get special access to all the things you need to start developing, without waiting
+for the rollout to complete. </p>
+
+<p class="warning"><b>Warning</b>: Do not publish any apps that use the new Google Play services
+APIs until the rollout is complete. Your apps will break on most user devices, which will
+degrade your user rating.</b>
+</p>
+
+<h2 style="margin-bottom: 0px;">1. Get Whitelisted for the Preview</h2><hr>
+
+<p>If you attended Google I/O, your registered Gmail account is automatically whitelisted for these
+preview resources. If you didn't attend Google I/O, sign up below to get access:</p>
+
+<a href="https://groups.google.com/forum/?hl=en#!forum/io14androidweardev">Get Whitelisted</a>
+
+<h2 style="margin-bottom: 0px;">2. Download Required Apps</h2><hr>
+<p>You'll need the following apps to get the most out of Android Wear:</p>
+
+
+<p>Here's a list of the apps you need:</p>
+<ul>
+<li><a href="https://play.google.com/apps/testing/com.google.android.gms">Google Play services</a>: Allows your Wear device to properly communicate with your handheld device. This is
+required to use the Android Wear Companion App.</li>
+  <li><a href="https://play.google.com/apps/testing/com.google.android.wearable.app">Android Wear
+  Companion</a>: The main user app to pair a handheld to a wearable and to provide syncing
+  of notifications and data.</li>
+  <li><a href="https://play.google.com/apps/testing/com.google.android.googlequicksearchbox">Google
+  Search</a>: A preview release of the Google Search handheld app that Wear communicates with
+  to carry out searches.</li>
+  <li><a href="https://play.google.com/apps/testing/com.google.android.keep">Google Keep</a>: To enable the "Take a note" command</li>
+  <li><a href="https://play.google.com/apps/testing/com.google.samples.apps.iosched">Google I/O 2014</a></li>
+ </ul>
+
+<p>To enable the preview versions of the apps, click each app link above and follow these
+instructions:</p>
+
+<ol>
+ <li>Click the <b>Become a Tester</b> button to opt-in to the preview version of the app. The page
+ confirms that you're a tester after clicking.</li>
+ <li>Click the <b>Download &lt;app name&gt; from the Play Store</b> link to go to Google Play
+ Store download page to get the app. The
+ following screenshot shows how the opt-in process looks like:
+<img style="margin-top:40px" src="/preview/images/opt-in.png"></li>
+ <li>When Google Play services is rolled out to all devices, go back to the app links provided
+  to opt-out of the preview versions of the apps. Check back here in a week for the status of
+  the rollout.</li>
+</ol>
+
+
+
+<h2 style="margin-bottom: 0px;">3. Start Building</h2><hr>
+<p>Check out the <a href="/training/building-wearables">Building Apps for Wearables</a>
+training classes for information on how to build for Wear.</p>
+    </div>
+
+   
+      
+
+  </div> <!-- end jd-content -->
+</div><!-- end doc-content -->
+</div> <!-- end body-content --> 
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/preview/images/android.png b/docs/html/preview/images/android.png
deleted file mode 100644
index 3aeaa98..0000000
--- a/docs/html/preview/images/android.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/preview/images/battery_historian.png b/docs/html/preview/images/battery_historian.png
index 5b0db74..f1d4e40 100644
--- a/docs/html/preview/images/battery_historian.png
+++ b/docs/html/preview/images/battery_historian.png
Binary files differ
diff --git a/docs/html/preview/images/battery_historian@2x.png b/docs/html/preview/images/battery_historian@2x.png
index dbb5d5e..8c8a87f 100644
--- a/docs/html/preview/images/battery_historian@2x.png
+++ b/docs/html/preview/images/battery_historian@2x.png
Binary files differ
diff --git a/docs/html/preview/images/hun-example.png b/docs/html/preview/images/hun-example.png
index 9613a92..251b938 100644
--- a/docs/html/preview/images/hun-example.png
+++ b/docs/html/preview/images/hun-example.png
Binary files differ
diff --git a/docs/html/preview/images/hun-example@2x.png b/docs/html/preview/images/hun-example@2x.png
index 3cb8f5b..5b98a361 100644
--- a/docs/html/preview/images/hun-example@2x.png
+++ b/docs/html/preview/images/hun-example@2x.png
Binary files differ
diff --git a/docs/html/preview/images/l-dev-prev.png b/docs/html/preview/images/l-dev-prev.png
index 95bad8c..eae6ede 100644
--- a/docs/html/preview/images/l-dev-prev.png
+++ b/docs/html/preview/images/l-dev-prev.png
Binary files differ
diff --git a/docs/html/preview/images/managed_apps_launcher.png b/docs/html/preview/images/managed_apps_launcher.png
index 983d904..b5ef407 100644
--- a/docs/html/preview/images/managed_apps_launcher.png
+++ b/docs/html/preview/images/managed_apps_launcher.png
Binary files differ
diff --git a/docs/html/preview/images/managed_apps_launcher@2x.png b/docs/html/preview/images/managed_apps_launcher@2x.png
index d298fd2..90d7d51 100644
--- a/docs/html/preview/images/managed_apps_launcher@2x.png
+++ b/docs/html/preview/images/managed_apps_launcher@2x.png
Binary files differ
diff --git a/docs/html/preview/images/opt-in.png b/docs/html/preview/images/opt-in.png
new file mode 100644
index 0000000..51754af
--- /dev/null
+++ b/docs/html/preview/images/opt-in.png
Binary files differ
diff --git a/docs/html/preview/index.html b/docs/html/preview/index.html
index 368db84..ff4572b 100644
--- a/docs/html/preview/index.html
+++ b/docs/html/preview/index.html
@@ -163,9 +163,9 @@
               platform officially launches.
             </div>
 
-            <img src="/preview/images/l-dev-prev.png" style=" margin:10px 0 0 100px" width="700px"/>
-            <div class="col-6" style="margin-left:630px; margin-top:-40px">
-   <a href="/preview/setup-sdk.html" class="landing-button landing-secondary" style="position:absolute;z-index:100;float:right;margin-top: 0px; background-color:#09c">Get Started</a><!--
+            <img src="/preview/images/l-dev-prev.png" style=" margin:0px 0 0 40px" width="860px"/>
+            <div class="col-6" style="margin-left:660px; margin-top:-105px">
+   <a href="/preview/setup-sdk.html" class="landing-button landing-secondary" style="position:absolute;z-index:100;float:right;margin-top: 0px;">Get Started</a><!--
             <p>Set up your environment and check out all the docs to get up and running.</p>-->
              
          
@@ -176,7 +176,7 @@
 
 
 
-<div class="landing-section landing-gray-background" style="margin-top:-80px; padding-bottom:20px">
+<div class="landing-section landing-gray-background" style="margin-top:-135px; padding-bottom:20px">
         <div class="wrap">
           <div class="cols">
 <div class="landing-body" style="margin-top:-80px" >
@@ -186,14 +186,14 @@
                 <p>A New UI Design</p>
                 <p class="landing-small">
                   Create a consistent experience across mobile and the web with
-                   material design, the new Google-wide standard.
+                   <b>material design</b>, the new Google-wide standard.
                 </p>
                 <p class="landing-small">
                   <a href="/preview/material/index.html">Learn about material</a>
                 </p>
               </div>
               <div class="col-4">
-                <p>A Rehauled Runtime</p>
+                <p>A New Runtime</p>
                 <p class="landing-small">
                   Test your apps and get them ready for <b>ART</b> (<b>A</b>ndroid <b>R</b>un<b>t</b>ime),
                   the default runtime in the next release.
@@ -205,21 +205,21 @@
               <div class="col-4">
                 <p style="width:230px">Enhanced Notifications</p>
                 <p class="landing-small">
-                   Get more control over where notifications appear,
-                   how they look, and automatic syncing to non-handheld devices.
+                   Get control over where notifications appear,
+                   how they look, and how they sync to non-handheld devices.
                 </p>
                 <p class="landing-small">
-                  <a href="/preview/api-overview.html#UI">Learn more</a>
+                  <a href="/preview/api-overview.html#UI">Learn about notifications</a>
                 </p>
               </div>
               <div class="col-4">
-                <p>Project Volta</p>
+                <p>Increased Efficiency</p>
                 <p class="landing-small">
-                  We've tuned the platform to be more energy efficient and
+                  <b>Project Volta</b> is our effort to make the platform energy efficient and
                   to give you more control over resource usage.
                 </p>
                 <p class="landing-small">
-                  <a href="/preview/api-overview.html#Power">Learn more</a>
+                  <a href="/preview/api-overview.html#Power">Learn about Project Volta</a>
                 </p>
               </div>
             </div>
@@ -257,7 +257,7 @@
                     Join the community of Android developers testing out the L Developer Preview and
                     share your thoughts and experiences.
                   </p><p class="landing-small">
-                    <a target="_blank" href="http://plus.google.com">
+                    <a target="_blank" href="https://plus.sandbox.google.com/communities/113159138894928487684">
                     Discuss on Google+</a>
                     </p>
                 </div>
diff --git a/docs/html/preview/license.jd b/docs/html/preview/license.jd
new file mode 100644
index 0000000..5ff52ba
--- /dev/null
+++ b/docs/html/preview/license.jd
@@ -0,0 +1,143 @@
+page.title=License Agreement
+
+@jd:body
+
+<p>
+To get started with the Android SDK Preview, you must agree to the following terms and conditions. 
+As described below, please note that this is a preview version of the Android SDK, subject to change, that you use at your own risk.  The Android SDK Preview is not a stable release, and may contain errors and defects that can result in serious damage to your computer systems, devices and data.
+</p>
+
+<p>
+This is the Android SDK Preview License Agreement (the “License Agreement”).
+</p>
+<div class="sdk-terms" style="height:auto;border:0;padding:0;width:700px">
+1. Introduction
+
+1.1 The Android SDK Preview (referred to in the License Agreement as the “Preview” and specifically including the Android system files, packaged APIs, and Preview library files, if and when they are made available) is licensed to you subject to the terms of the License Agreement. The License Agreement forms a legally binding contract between you and Google in relation to your use of the Preview.
+
+1.2 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time.
+
+1.3 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.
+
+2. Accepting the License Agreement
+
+2.1 In order to use the Preview, you must first agree to the License Agreement. You may not use the Preview if you do not accept the License Agreement.
+
+2.2 By clicking to accept and/or using the Preview, you hereby agree to the terms of the License Agreement.
+
+2.3 You may not use the Preview and may not accept the License Agreement if you are a person barred from receiving the Preview under the laws of the United States or other countries including the country in which you are resident or from which you use the Preview.
+
+2.4 If you will use the Preview internally within your company or organization you agree to be bound by the License Agreement on behalf of your employer or other entity, and you represent and warrant that you have full legal authority to bind your employer or such entity to the License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the Preview on behalf of your employer or other entity.
+
+3. Preview License from Google
+
+3.1 Subject to the terms of the License Agreement, Google grants you a royalty-free, non-assignable, non-exclusive, non-sublicensable, limited, revocable license to use the Preview, personally or internally within your company or organization, solely to develop applications to run on the Android platform.
+
+3.2 You agree that Google or third parties owns all legal right, title and interest in and to the Preview, including any Intellectual Property Rights that subsist in the Preview. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you.
+
+3.3 You may not use the Preview for any purpose not expressly permitted by the License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the Preview or any part of the Preview; or (b) load any part of the Preview onto a mobile handset or any other hardware device except a personal computer, combine any part of the Preview with other software, or distribute any software or device incorporating a part of the Preview.
+
+3.4 You agree that you will not take any actions that may cause or result in the fragmentation of Android, including but not limited to distributing, participating in the creation of, or promoting in any way a software development kit derived from the Preview.
+
+3.5 Use, reproduction and distribution of components of the Preview licensed under an open source software license are governed solely by the terms of that open source software license and not the License Agreement. You agree to remain a licensee in good standing in regard to such open source software licenses under all the rights granted and to refrain from any actions that may terminate, suspend, or breach such rights.
+
+3.6 You agree that the form and nature of the Preview that Google provides may change without prior notice to you and that future versions of the Preview may be incompatible with applications developed on previous versions of the Preview. You agree that Google may stop (permanently or temporarily) providing the Preview (or any features within the Preview) to you or to users generally at Google's sole discretion, without prior notice to you.
+
+3.7 Nothing in the License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features.
+
+3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the Preview.
+
+4. Use of the Preview by You
+
+4.1 Google agrees that nothing in the License Agreement gives Google any right, title or interest from you (or your licensors) under the License Agreement in or to any software applications that you develop using the Preview, including any intellectual property rights that subsist in those applications.
+
+4.2 You agree to use the Preview and write applications only for purposes that are permitted by (a) the License Agreement, and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries). 
+
+4.3 You agree that if you use the Preview to develop applications, you will protect the privacy and legal rights of users. If users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If users provide you with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, each user has given you permission to do so.
+
+4.4 You agree that you will not engage in any activity with the Preview, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of Google or any third party.
+
+4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android and/or applications for Android, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so.
+
+4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under the License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach.
+
+4.7 The Preview is in development, and your testing and feedback are an important part of the development process. By using the Preview, you acknowledge that implementation of some features are still under development and that you should not rely on the Preview having the full functionality of a stable release. You agree not to publicly distribute or ship any application using this Preview as this Preview will no longer be supported after the official Android SDK is released.
+
+5. Your Developer Credentials
+
+5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials.
+
+6. Privacy and Information
+
+6.1 In order to continually innovate and improve the Preview, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the Preview are being used and how they are being used. Before any of this information is collected, the Preview will notify you and seek your consent. If you withhold consent, the information will not be collected.
+
+6.2 The data collected is examined in the aggregate to improve the Preview and is maintained in accordance with Google's Privacy Policy located at http://www.google.com/policies/privacy/.
+
+7. Third Party Applications
+
+7.1 If you use the Preview to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources.
+
+7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners.
+
+7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party.
+
+8. Using Google APIs
+
+8.1 Google APIs
+
+8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service.
+
+8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so.
+
+9. Terminating the License Agreement
+
+9.1 the License Agreement will continue to apply until terminated by either you or Google as set out below.
+
+9.2 If you want to terminate the License Agreement, you may do so by ceasing your use of the Preview and any relevant developer credentials.
+
+9.3 Google may at any time, terminate the License Agreement, with or without cause, upon notice to you.
+
+9.4 The License Agreement will automatically terminate without notice or other action upon the earlier of:
+(A) when Google ceases to provide the Preview or certain parts of the Preview to users in the country in which you are resident or from which you use the service; and
+(B) Google issues a final release version of the Android SDK.
+
+9.5 When the License Agreement is terminated, the license granted to you in the License Agreement will terminate, you will immediately cease all use of the Preview, and the provisions of paragraphs 10, 11, 12 and 14 shall survive indefinitely.
+
+10. DISCLAIMERS
+
+10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE PREVIEW IS AT YOUR SOLE RISK AND THAT THE PREVIEW IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
+
+10.2 YOUR USE OF THE PREVIEW AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE PREVIEW IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE. WITHOUT LIMITING THE FOREGOING, YOU UNDERSTAND THAT THE PREVIEW IS NOT A STABLE RELEASE AND MAY CONTAIN ERRORS, DEFECTS AND SECURITY VULNERABILITIES THAT CAN RESULT IN SIGNIFICANT DAMAGE, INCLUDING THE COMPLETE, IRRECOVERABLE LOSS OF USE OF YOUR COMPUTER SYSTEM OR OTHER DEVICE.
+
+10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+
+11. LIMITATION OF LIABILITY
+
+11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
+
+12. Indemnification
+
+12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys’ fees) arising out of or accruing from (a) your use of the Preview, (b) any application you develop on the Preview that infringes any Intellectual Property Rights of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you of the License Agreement.
+
+13. Changes to the License Agreement
+
+13.1 Google may make changes to the License Agreement as it distributes new versions of the Preview. When these changes are made, Google will make a new version of the License Agreement available on the website where the Preview is made available.
+
+14. General Legal Terms
+
+14.1 the License Agreement constitutes the whole legal agreement between you and Google and governs your use of the Preview (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the Preview.
+
+14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in the License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google.
+
+14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of the License Agreement is invalid, then that provision will be removed from the License Agreement without affecting the rest of the License Agreement. The remaining provisions of the License Agreement will continue to be valid and enforceable.
+
+14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to the License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of the License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to the License Agreement.
+
+14.5 EXPORT RESTRICTIONS. THE PREVIEW IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE PREVIEW. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
+
+14.6 The License Agreement may not be assigned or transferred by you without the prior written approval of Google, and any attempted assignment without such approval will be void. You shall not delegate your responsibilities or obligations under the License Agreement without the prior written approval of Google.
+
+14.7 The License Agreement, and your relationship with Google under the License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from the License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
+
+
+</div>
\ No newline at end of file
diff --git a/docs/html/preview/preview_toc.cs b/docs/html/preview/preview_toc.cs
index 5920ecc..75703a8 100644
--- a/docs/html/preview/preview_toc.cs
+++ b/docs/html/preview/preview_toc.cs
@@ -2,11 +2,7 @@
 
 
   <li class="nav-section">
-    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/setup-sdk.html">Set up the Preview SDK
-      </a></div>
-  </li>
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/setup-devices.html">Set Up Hardware and AVDs
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/setup-sdk.html">Set up the SDK
       </a></div>
   </li>
   <li class="nav-section">
@@ -70,7 +66,7 @@
   <li class="nav-section">
     <div class="nav-section-header empty">
 
-      <a href="<?cs var:toroot ?>preview/l-developer-preview-reference.zip">Reference</a>
+      <a href="<?cs var:toroot ?>preview/reference.html">Reference</a>
 
     </div>
   </li>
@@ -81,7 +77,12 @@
   </li>
   <li class="nav-section">
     <div class="nav-section-header empty">
-      <a href="<?cs var:toroot ?>preview/tos.html">Terms of Service</a>
+      <a href="<?cs var:toroot ?>preview/license.html">License Agreement</a>
+      </div>
+  </li>
+  <li class="nav-section" style="margin: 20px 0 0 3px;">
+    <div class="nav-section-header paging-links empty">
+      <a href="<?cs var:toroot ?>index.html" class="prev-page-link">Developer Home</a>
       </div>
   </li>
 </ul>
diff --git a/docs/html/preview/reference.jd b/docs/html/preview/reference.jd
new file mode 100644
index 0000000..f70f7a2
--- /dev/null
+++ b/docs/html/preview/reference.jd
@@ -0,0 +1,13 @@
+page.title=Reference
+
+@jd:body
+
+<p>The reference documentation and API difference report are available as downloadable packages.
+</p>
+
+<ul>
+  <li><a href="{@docRoot}preview/l-developer-preview-reference.zip">L
+  Developer Preview reference</a></li>
+  <li><a href="{@docRoot}preview/l-developer-preview-api-diff.zip">L
+  Developer Preview difference report</a></li>
+</ul>
\ No newline at end of file
diff --git a/docs/html/preview/samples.jd b/docs/html/preview/samples.jd
index 67404b6..9bccb31 100644
--- a/docs/html/preview/samples.jd
+++ b/docs/html/preview/samples.jd
@@ -2,15 +2,4 @@
 
 @jd:body
 
-<p>The code samples for the L Developer Preview are available in the Android SDK Manager under the
-L Preview section. Here is a summary of everything that is available:</p>
-
-<ul>
-  <li></li>
-  <li></li>
-  <li></li>
-  <li></li>
-  <li></li>
-  <li></li>
-  <li></li>
- </ul>
+<p>&nbsp;</p>
\ No newline at end of file
diff --git a/docs/html/preview/setup-devices.jd b/docs/html/preview/setup-devices.jd
deleted file mode 100644
index 86e4845..0000000
--- a/docs/html/preview/setup-devices.jd
+++ /dev/null
@@ -1,90 +0,0 @@
-page.title=Setting Up Hardware and AVDs
-@jd:body
-
-<p>The Android L developer preview provides you with 32-bit system images
-to flash the following devices:
-</p>
-
-<ul>
-  <li>Nexus 5</li>
-  <li>Nexus 7 Wi-Fi (version 2, released in 2013)</li>
-</ul>
-
-<p>In addition, you also get the emulator system images, which includes
-experimental 64-bit system images along with standard 32-bit system images.
-</p>
-
-<h2>Installing the L Preview System Image</h2>
-
-<!-- Will we get an official warning text from the lawyercats? Is this it? -->
-<p class="warning"><b>Warning</b>: This is a preview version of the Android
-system image, and is subject to change. Your use of this system image is
-governed by the Android SDK Preview License Agreement. The Android preview
-system image is not a stable release, and may contain errors and defects that
-can result in damage to your computer systems, devices, and data. The preview
-Android system image is not subject to the same testing as the factory OS and
-can cause your phone and installed services and applications to stop working.
-</p>
-
-
-<ol>
-  <li>Download and extract the Android Developer Preview package to a directory
-  (which we'll call <code>&lt;l_download_dir&gt;</code> in these
-  instructions).</li>
-  <li>Connect your powered-off Android device to your development machine. Put
-  the device in fastboot mode by pressing and holding the following buttons:
-    <ul>
-    <li><strong>Nexus 5:</strong> <i>volume down</i> + <i>volume up</i> +
-        <i>power</i></li>
-    <li><strong>Nexus 7:</strong> <i>volume down</i> + <i>power</i> </li>
-    </ul>
-    <p class="note">Alternatively, you can enter fastboot mode by booting up
-    the device and running <code>adb reboot bootloader</code> with USB debugging
-    turned on.</p>
-  </li>
-  <li>Follow the instructions at
-  <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
-  to set up your system for flashing devices.</li>
-  <li>Run the <code>&lt;l_download_dir&gt;/flash-all</code> script
-  corresponding to your platform. This script flashes all of the system data
-  onto the phone.</li> <!-- Confirm names of flash scripts -->
-  <li>(Optional) After flashing is complete, lock your device's bootloader by
-  putting it in   fastboot mode and running <code>fastboot oem lock</code>.
-  (This does not wipe   your device.) Once you do this,  you will not be able to
-  flash your device until you run   run <code>fastboot oem   unlock</code>,
-  which unlocks the bootloader and wipes your device. We recommend you leave the
-  bootloader unlocked until you are done with flashing the device.</li>
-</ol>
-
-<h3>Reverting a Device to Factory Specifications</h3>
-
-  <p>If you want to uninstall the L Preview and revert the device to factory
-specifications, go to <a href="http://developers.google.com/android
-/nexus/images">developers.google.com/android</a> and download the image you want
-to flash to for your device. Follow the instructions on that page to flash the
-image to your device.</p>
-
-
-<h2>Setting up an AVD</h2>
-
-<p>You can set up <a href="{@docRoot}tools/devices/">Android Virtual Devices
-(AVD)</a> and use the emulator to build and test apps with the L Preview.</p>
-
-<p>To create an AVD with the AVD Manager:</p>
-
-<ol>
-  <li>Install the L Preview SDK in your development environment, as described
-      in <a href="{@docRoot}preview/setup-sdk.html">Setting Up the Preview
-      SDK.</a></li>
-  <li>Follow the steps in
-      <a href="{@docRoot}tools/devices/managing-avds.html">Managing AVDs with AVD
-      Manager</a>. Use the following settings:
-    <ul>
-      <li><b>Device:</b> Either Nexus 5 or Nexus 7</li>
-      <li><b>Target:</b> <!-- Confirm exact text when we have final distro -->
-       Android L (Preview) - API Level L</li>
-    </ul>
-    <!-- Confirm this works when you can download image through SDK manager! -->
-  </li>
-</ol>
-
diff --git a/docs/html/preview/setup-sdk.jd b/docs/html/preview/setup-sdk.jd
index 32a33b6..66262dc 100644
--- a/docs/html/preview/setup-sdk.jd
+++ b/docs/html/preview/setup-sdk.jd
@@ -20,7 +20,96 @@
     <b>Install</b>.</li>
 </ol>
 
-<h2>Set up your environment</h2>
+<h2>Set Up Hardware and AVDs</h2>
+
+<p>The Android L developer preview provides you with 32-bit system images
+to flash the following devices:
+</p>
+
+<ul>
+  <li>Nexus 5</li>
+  <li>Nexus 7 Wi-Fi (version 2, released in 2013)</li>
+</ul>
+
+<p>In addition, you also get the emulator system images, which includes
+experimental 64-bit system images along with standard 32-bit system images.
+</p>
+
+<h3>Instal the L Preview System Image</h3>
+
+<!-- Will we get an official warning text from the lawyercats? Is this it? -->
+<p class="warning"><b>Warning</b>: This is a preview version of the Android
+system image, and is subject to change. Your use of this system image is
+governed by the Android SDK Preview License Agreement. The Android preview
+system image is not a stable release, and may contain errors and defects that
+can result in damage to your computer systems, devices, and data. The preview
+Android system image is not subject to the same testing as the factory OS and
+can cause your phone and installed services and applications to stop working.
+</p>
+
+
+<ol>
+  <li>Download and extract the Android Developer Preview package to a directory
+  (which we'll call <code>&lt;l_download_dir&gt;</code> in these
+  instructions).</li>
+  <li>Connect your powered-off Android device to your development machine. Put
+  the device in fastboot mode by pressing and holding the following buttons:
+    <ul>
+    <li><strong>Nexus 5:</strong> <i>volume down</i> + <i>volume up</i> +
+        <i>power</i></li>
+    <li><strong>Nexus 7:</strong> <i>volume down</i> + <i>power</i> </li>
+    </ul>
+    <p class="note">Alternatively, you can enter fastboot mode by booting up
+    the device and running <code>adb reboot bootloader</code> with USB debugging
+    turned on.</p>
+  </li>
+  <li>Follow the instructions at
+  <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
+  to set up your system for flashing devices.</li>
+  <li>Run the <code>&lt;l_download_dir&gt;/flash-all</code> script
+  corresponding to your platform. This script flashes all of the system data
+  onto the phone.</li> <!-- Confirm names of flash scripts -->
+  <li>(Optional) After flashing is complete, lock your device's bootloader by
+  putting it in   fastboot mode and running <code>fastboot oem lock</code>.
+  (This does not wipe   your device.) Once you do this,  you will not be able to
+  flash your device until you run   run <code>fastboot oem   unlock</code>,
+  which unlocks the bootloader and wipes your device. We recommend you leave the
+  bootloader unlocked until you are done with flashing the device.</li>
+</ol>
+
+<h3>Revert a Device to Factory Specifications</h3>
+
+  <p>If you want to uninstall the L Preview and revert the device to factory
+specifications, go to <a href="http://developers.google.com/android
+/nexus/images">developers.google.com/android</a> and download the image you want
+to flash to for your device. Follow the instructions on that page to flash the
+image to your device.</p>
+
+
+<h3>Set up an AVD</h3>
+
+<p>You can set up <a href="{@docRoot}tools/devices/">Android Virtual Devices
+(AVD)</a> and use the emulator to build and test apps with the L Preview.</p>
+
+<p>To create an AVD with the AVD Manager:</p>
+
+<ol>
+  <li>Install the L Preview SDK in your development environment, as described
+      in <a href="{@docRoot}preview/setup-sdk.html">Setting Up the Preview
+      SDK.</a></li>
+  <li>Follow the steps in
+      <a href="{@docRoot}tools/devices/managing-avds.html">Managing AVDs with AVD
+      Manager</a>. Use the following settings:
+    <ul>
+      <li><b>Device:</b> Either Nexus 5 or Nexus 7</li>
+      <li><b>Target:</b> <!-- Confirm exact text when we have final distro -->
+       Android L (Preview) - API Level L</li>
+    </ul>
+    <!-- Confirm this works when you can download image through SDK manager! -->
+  </li>
+</ol>
+
+<h2>Create a Project</h2>
 
 <ol>
   <li>Create a new Android project with the following properties:
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index 23ce6ff..9ab25dd 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -2,21 +2,85 @@
 
 @jd:body
 
-<p>If you've encountered bugs or have feedback about the L Developer Preview, create
-an issue on our bug tracker</p>
+<p>If you've encountered bugs or have feedback about the L Developer Preview,
+<a href="https://code.google.com/p/android-developer-preview/">create an issue</a> on
+our issue tracker.</p>
 
-<p>Go to the Bug Tracker</p>
+<p>For more support,
+<a href="https://plus.google.com/communities/113159138894928487684">join
+the L Developer Preview Google+ community</a> to discuss your development experiences.
 
-<h2>Release Notes</h2>
 
+<h2 id="ReleaseNotes">Release Notes</h2>
 <p>June 25, 2014 - Initial Release of the L Developer Preview</p>
 
+<h3 id="UserInterface">User interface</h3>
 <ul>
-  <li></li>
-  <li></li>
-  <li></li>
-  <li></li>
-  <li></li>
-  <li></li>
-  <li></li>
- </ul>
+<li>If your app launches an activity with
+{@link android.app.Activity#startActivity startActivity()}
+and an {@link android.content.Intent} set to
+{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET}, the
+activity shows up as a separate task in the Recent apps screen. This is the
+same behavior as though your app used {@code Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
+(see <a href="{@docRoot}preview/api-overview.html#Recents">Concurrent
+documents and activities in the Recents screen</a>). If you want your activity
+to remain in the same task that launched it, use
+{@link android.app.Activity#startActivityForResult
+startActivityForResult()} instead.</li>
+<li>System-rendered shadows for user interface (UI) elements in views may
+appear with visible spiky edges. To avoid this visual artifact, use a higher
+<a href="{@docRoot}preview/material/views-shadows.html#elevation">view
+elevation</a>.</li>
+<li>On very tall or wide views, view shadows may appear with additional rough
+visual artifacts around the view edges. To minimize this, avoid using view
+shadows with very narrow views.</li>
+<li>The {@code android.graphics.drawable.RippableDrawable} class does not
+respond to pointer location changes, except when the drawable is set as a
+{@link android.view.View} background.</li>
+</ul>
+
+<h3 id="Multimedia">Multimedia</h3>
+<ul>
+<li>The {@code android.hardware.camera2} APIs are supported only on Nexus 5
+devices.</li>
+<li>Saving a DNG file with the new {@code android.hardware.camera2.DngCreator}
+API fails if lens shading compensation map generation is not enabled. To
+capture images to DNG files, add the following code when creating your capture
+requests:
+<pre>
+CaptureRequest.Builder stillCaptureRequest =
+        mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+
+stillCaptureRequest.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE,
+        CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON);
+</pre></li>
+<li>Portions of the internal audio pipeline do not support floating-point format.</li>
+<li>The {@code android.media.AudioTrack.write(float[], int, int, int)} method
+currently does not work. Use the
+{@link android.media.AudioTrack#write(short[], int, int)
+AudioTrack.write(short[], int, int)} method instead.</li>
+</ul>
+
+<h3 id="UserInput">User input</h3>
+<ul><li>The System UI may crash unexpectedly while the device is charging, if
+	the locale is set to {@code fr} (FRENCH).</li></ul>
+
+<h3 id="Wireless">Wireless and Connectivity</h3>
+<ul><li>The {@code android.bluetooth.le} APIs are supported only on Nexus 5
+devices.</li></ul>
+
+<h3 id="Enterprise">Enterprise</h3>
+<ul>
+<li>The device may crash unexpectedly in these situations when using
+Android for Work functionality:
+<ul>
+<li>The user attempts to share a webpage (via <strong>Menu &gt; Share</strong>)
+from a non-managed Chrome app to a managed Gmail app.</li>
+<li>The user attempts to share a webpage via Bluetooth from a managed Chrome app.</li>
+<li>The user attempts to share a webpage via Android Beam from a managed Chrome app.</li>
+</ul>
+</li>
+<li>Deleting the managed work profile (profile owner) may take several minutes
+to complete. You cannot create a new managed profile until the deletion
+operation is over.</li>
+</ul>
diff --git a/docs/html/preview/tos.jd b/docs/html/preview/tos.jd
deleted file mode 100644
index 602439f..0000000
--- a/docs/html/preview/tos.jd
+++ /dev/null
@@ -1,9 +0,0 @@
-page.title=License Agreement
-
-@jd:body
-
-<p><!-- Will this link change before we publish (to a clean version of the doc)?
-  Or will we scrub the doc's comments & revision history? -->
-<a href="https://docs.google.com/a/google.com/document/d/1OixnM1Q890ExOzDB3Z-FDD6Sb2kF4uZQiMxsYVII8F0/edit?usp=sharing">L
-Preview Terms of Service</a>
-</p>
\ No newline at end of file
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 3671726..304b53d 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -3,8 +3,8 @@
 @jd:body
 
 <style>
-.paging-links {
-  margin:0 0 80px;
+p.paging-links {
+  margin:0 0 40px;
 }
 .paging-links .next-page-link {
   right:initial;
@@ -14,6 +14,10 @@
   margin-bottom:1em;
   background:#eee;
 }
+.landing-button {
+  min-width: 155px;
+  text-align: center;
+}
 </style>
 
 
@@ -316,39 +320,32 @@
 
 
 <!-- ################    DEFAULT    ##################### -->
-<style>
-h3.large-link {
-  display:inline-block;
-  width:100%;
-  text-align:center;
-  border:1px solid #258aaf;
-  padding:10px 0;
-  color:inherit;
-}
-</style>
+
 
 <div id="default" style="display:none">
 
-<p>If you haven't already done so, <b><a href="{@docRoot}sdk/index.html">click here to download
+<p>If you haven't already, <b><a href="{@docRoot}sdk/index.html">download
 the Android SDK</a></b>. </p>
 
-<p>Otherwise, select which SDK package you want to install:</p>
+<p>Then, select which SDK package you want to install:</p>
 
-<div class="cols" style="margin-bottom:60px">
-<div class="col-4">
-<a href="{@docRoot}sdk/installing/index.html?pkg=adt">
-<h3 class="large-link">Eclipse ADT</h3>
+<div class="cols" style="margin:30px 0 60px">
+<div class="col-4" style="margin-left:0">
+<a href="{@docRoot}sdk/installing/index.html?pkg=adt" class="landing-button landing-secondary">
+Eclipse ADT
 </a>
 </div>
 
 <div class="col-4">
-<a href="{@docRoot}sdk/installing/index.html?pkg=studio">
-<h3 class="large-link">Android Studio</h3></a>
+<a href="{@docRoot}sdk/installing/index.html?pkg=studio" class="landing-button landing-secondary">
+Android Studio
+</a>
 </div>
 
 <div class="col-4">
-<a href="{@docRoot}sdk/installing/index.html?pkg=tools">
-<h3 class="large-link">Stand-alone SDK Tools</h3></a>
+<a href="{@docRoot}sdk/installing/index.html?pkg=tools" class="landing-button landing-secondary">
+Stand-alone SDK Tools
+</a>
 </div>
 </div>
 
diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd
index 3e7652c..5c48e49 100644
--- a/docs/html/tv/index.jd
+++ b/docs/html/tv/index.jd
@@ -204,13 +204,13 @@
             <div class="landing-breakout cols">
 
               <div class="col-8">
-                <a href="{@docRoot}preview/setup-sdk.html" class="landing-button landing-secondary">
+                <a href="{@docRoot}preview/setup-sdk.html" class="landing-button landing-primary">
                   Download the Preview SDK
                 </a>
               </div>
 
               <div class="col-8">
-                <a href="{@docRoot}preview/tv/adt-1/request.html" class="landing-button landing-secondary">
+                <a href="{@docRoot}preview/tv/adt-1/request.html" class="landing-button landing-primary">
                   Request ADT-1 Developer Kit
                 </a>
               </div>
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index 0d9325d..1de09ee 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -68,7 +68,7 @@
     </div> <!-- end .landing-section .landing-hero -->
 
 
-    <div class="landing-rest-of-page">
+    <div class="landing-rest-of-page" style="margin-top:80px">
       <div class="landing-section" id="extending-android-to-wearables">
         <div class="wrap">
           <div class="landing-section-header">
@@ -183,6 +183,56 @@
         </div> <!-- end .wrap -->
       </div> <!-- end .landing-section -->
 
+      <div class="landing-section landing-white-background">
+        <div class="wrap">
+          <div class="landing-section-header">
+            <div class="landing-h2">Building an Ecosystem</div>
+            <div class="landing-body landing-align-center">
+              <p class="landing-small">
+                We’re working with several partners to bring you watches powered by Android Wear later this year!
+              </p>
+            </div>
+          </div>
+
+          <div class="landing-partners cols">
+            <div class="col-4">
+              <img src="/wear/images/partners/asus.png" alt="Asus">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/broadcom.png" alt="Broadcom">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/fossil.png" alt="Fossil">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/htc.png" alt="HTC">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/intel.png" alt="Intel">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/lg.png" alt="LG">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/mediatek.png" alt="Mediatek">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/mips.png" alt="MIPS">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/motorola.png" alt="Motorola">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/qualcomm.png" alt="Qualcomm">
+            </div>
+            <div class="col-4">
+              <img src="/wear/images/partners/samsung.png" alt="Samsung">
+            </div>
+          </div>
+        </div> <!-- end .wrap -->
+      </div>
+
+
       <div class="landing-section landing-red-background">
         <div class="wrap">
           <div class="landing-section-header">
@@ -196,7 +246,7 @@
             </div>
           </div>
           <div class="landing-body">
-            <a href="{@docRoot}training/building-wearables.html" class="landing-button landing-secondary" style="margin-top: 20px;">
+            <a href="{@docRoot}training/building-wearables.html" class="landing-button landing-primary" style="margin-top: 20px;">
               Get Started
             </a>
           </div>
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 968c0ec..c787fb0 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -34,10 +34,91 @@
 import java.util.ArrayList;
 
 /**
- * AnimatedVectorDrawable can use ObjectAnimator and AnimatorSet to animate
- * the property of the VectorDrawable.
+ * This class uses {@link android.animation.ObjectAnimator} and
+ * {@link android.animation.AnimatorSet} to animate the properties of a
+ * {@link android.graphics.drawable.VectorDrawable} to create an animated drawable.
+ * <p>
+ * AnimatedVectorDrawable are normally defined as 3 separate XML files.
+ * </p>
+ * <p>
+ * First is the XML file for {@link android.graphics.drawable.VectorDrawable}.
+ * Note that we allow the animation happen on the group's attributes and path's
+ * attributes, which requires they are uniquely named in this xml file. Groups
+ * and paths without animations do not need names.
+ * </p>
+ * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
+ * <pre>
+ * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
+ *     &lt;size
+ *         android:height=&quot;64dp&quot;
+ *         android:width=&quot;64dp&quot; /&gt;
+ *     &lt;viewport
+ *         android:viewportHeight=&quot;600&quot;
+ *         android:viewportWidth=&quot;600&quot; /&gt;
+ *     &lt;group
+ *         android:name=&quot;rotationGroup&quot;
+ *         android:pivotX=&quot;300.0&quot;
+ *         android:pivotY=&quot;300.0&quot;
+ *         android:rotation=&quot;45.0&quot; &gt;
+ *         &lt;path
+ *             android:name=&quot;v&quot;
+ *             android:fill=&quot;#000000&quot;
+ *             android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
+ *     &lt;/group&gt;
+ * &lt;/vector&gt;
+ * </pre></li>
+ * <p>
+ * Second is the AnimatedVectorDrawable's xml file, which defines the target
+ * VectorDrawable, the target paths and groups to animate, the properties of the
+ * path and group to animate and the animations defined as the ObjectAnimators
+ * or AnimatorSets.
+ * </p>
+ * <li>Here is a simple AnimatedVectorDrawable defined in this avd.xml file.
+ * Note how we use the names to refer to the groups and paths in the vectordrawable.xml.
+ * <pre>
+ * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+ *   android:drawable=&quot;@drawable/vectordrawable&quot; &gt;
+ *     &lt;target
+ *         android:name=&quot;rotationGroup&quot;
+ *         android:animation=&quot;@anim/rotation&quot; /&gt;
+ *     &lt;target
+ *         android:name=&quot;v&quot;
+ *         android:animation=&quot;@anim/path_morph&quot; /&gt;
+ * &lt;/animated-vector&gt;
+ * </pre></li>
+ * <p>
+ * Last is the Animator xml file, which is the same as a normal ObjectAnimator
+ * or AnimatorSet.
+ * To complete this example, here are the 2 animator files used in avd.xml:
+ * rotation.xml and path_morph.xml.
+ * </p>
+ * <li>Here is the rotation.xml, which will rotate the target group for 360 degrees.
+ * <pre>
+ * &lt;objectAnimator
+ *     android:duration=&quot;6000&quot;
+ *     android:propertyName=&quot;rotation&quot;
+ *     android:valueFrom=&quot;0&quot;
+ *     android:valueTo=&quot;360&quot; /&gt;
+ * </pre></li>
+ * <li>Here is the path_morph.xml, which will morph the path from one shape to
+ * the other. Note that the paths must be compatible for morphing.
+ * In more details, the paths should have exact same length of commands , and
+ * exact same length of parameters for each commands.
+ * Note that the path string are better stored in strings.xml for reusing.
+ * <pre>
+ * &lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
+ *     &lt;objectAnimator
+ *         android:duration=&quot;3000&quot;
+ *         android:propertyName=&quot;pathData&quot;
+ *         android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0   -70,70z&quot;
+ *         android:valueTo=&quot;M300,70 l 0,-70 70,0  0,140 -70,0 z&quot;
+ *         android:valueType=&quot;pathType&quot;/&gt;
+ * &lt;/set&gt;
+ * </pre></li>
  *
- * @hide
+ * @attr ref android.R.styleable#AnimatedVectorDrawable_drawable
+ * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_name
+ * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_animation
  */
 public class AnimatedVectorDrawable extends Drawable implements Animatable {
     private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName();
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 0a394d5..e080375 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -757,7 +757,18 @@
 
         final int tileMode = a.getInt(R.styleable.BitmapDrawable_tileMode, TILE_MODE_UNDEFINED);
         if (tileMode != TILE_MODE_UNDEFINED) {
-            setTileModeInternal(tileMode);
+            final Shader.TileMode mode = parseTileMode(tileMode);
+            setTileModeXY(mode, mode);
+        }
+
+        final int tileModeX = a.getInt(R.styleable.BitmapDrawable_tileModeX, TILE_MODE_UNDEFINED);
+        if (tileModeX != TILE_MODE_UNDEFINED) {
+            setTileModeX(parseTileMode(tileModeX));
+        }
+
+        final int tileModeY = a.getInt(R.styleable.BitmapDrawable_tileModeY, TILE_MODE_UNDEFINED);
+        if (tileModeY != TILE_MODE_UNDEFINED) {
+            setTileModeY(parseTileMode(tileModeY));
         }
 
         // Update local properties.
@@ -783,20 +794,16 @@
         }
     }
 
-    private void setTileModeInternal(final int tileMode) {
+    private static Shader.TileMode parseTileMode(int tileMode) {
         switch (tileMode) {
-            case TILE_MODE_DISABLED:
-                setTileModeXY(null, null);
-                break;
             case TILE_MODE_CLAMP:
-                setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
-                break;
+                return Shader.TileMode.CLAMP;
             case TILE_MODE_REPEAT:
-                setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
-                break;
+                return Shader.TileMode.REPEAT;
             case TILE_MODE_MIRROR:
-                setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
-                break;
+                return Shader.TileMode.MIRROR;
+            default:
+                return null;
         }
     }
 
@@ -919,7 +926,9 @@
     }
 
     /**
-     * Initializes local dynamic properties from state.
+     * Initializes local dynamic properties from state. This should be called
+     * after significant state changes, e.g. from the One True Constructor and
+     * after inflating or applying a theme.
      */
     private void initializeWithState(BitmapState state, Resources res) {
         if (res != null) {
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 005b8ef..0ccce93 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -135,18 +135,17 @@
     private Paint mStrokePaint;   // optional, set by the caller
     private ColorFilter mColorFilter;   // optional, set by the caller
     private int mAlpha = 0xFF;  // modified by the caller
-    private boolean mDither;
 
     private final Path mPath = new Path();
     private final RectF mRect = new RectF();
 
     private Paint mLayerPaint;    // internal, used if we use saveLayer()
-    private boolean mRectIsDirty;   // internal state
+    private boolean mGradientIsDirty;   // internal state
     private boolean mMutated;
     private Path mRingPath;
     private boolean mPathIsDirty = true;
 
-    /** Current gradient radius, valid when {@link #mRectIsDirty} is false. */
+    /** Current gradient radius, valid when {@link #mGradientIsDirty} is false. */
     private float mGradientRadius;
 
     /**
@@ -384,7 +383,7 @@
      */
     public void setGradientType(int gradient) {
         mGradientState.setGradientType(gradient);
-        mRectIsDirty = true;
+        mGradientIsDirty = true;
         invalidateSelf();
     }
 
@@ -403,7 +402,7 @@
      */
     public void setGradientCenter(float x, float y) {
         mGradientState.setGradientCenter(x, y);
-        mRectIsDirty = true;
+        mGradientIsDirty = true;
         invalidateSelf();
     }
 
@@ -421,7 +420,7 @@
      */
     public void setGradientRadius(float gradientRadius) {
         mGradientState.setGradientRadius(gradientRadius, TypedValue.COMPLEX_UNIT_PX);
-        mRectIsDirty = true;
+        mGradientIsDirty = true;
         invalidateSelf();
     }
 
@@ -455,7 +454,7 @@
      */
     public void setUseLevel(boolean useLevel) {
         mGradientState.mUseLevel = useLevel;
-        mRectIsDirty = true;
+        mGradientIsDirty = true;
         invalidateSelf();
     }
 
@@ -483,7 +482,7 @@
      */
     public void setOrientation(Orientation orientation) {
         mGradientState.mOrientation = orientation;
-        mRectIsDirty = true;
+        mGradientIsDirty = true;
         invalidateSelf();
     }
 
@@ -501,7 +500,7 @@
      */
     public void setColors(int[] colors) {
         mGradientState.setColors(colors);
-        mRectIsDirty = true;
+        mGradientIsDirty = true;
         invalidateSelf();
     }
 
@@ -543,7 +542,7 @@
             if (mLayerPaint == null) {
                 mLayerPaint = new Paint();
             }
-            mLayerPaint.setDither(mDither);
+            mLayerPaint.setDither(st.mDither);
             mLayerPaint.setAlpha(mAlpha);
             mLayerPaint.setColorFilter(mColorFilter);
 
@@ -561,14 +560,14 @@
                 individual paints
             */
             mFillPaint.setAlpha(currFillAlpha);
-            mFillPaint.setDither(mDither);
+            mFillPaint.setDither(st.mDither);
             mFillPaint.setColorFilter(mColorFilter);
-            if (mColorFilter != null && mGradientState.mColorStateList == null) {
+            if (mColorFilter != null && st.mColorStateList == null) {
                 mFillPaint.setColor(mAlpha << 24);
             }
             if (haveStroke) {
                 mStrokePaint.setAlpha(currStrokeAlpha);
-                mStrokePaint.setDither(mDither);
+                mStrokePaint.setDither(st.mDither);
                 mStrokePaint.setColorFilter(mColorFilter);
             }
         }
@@ -638,10 +637,11 @@
 
     private void buildPathIfDirty() {
         final GradientState st = mGradientState;
-        if (mPathIsDirty || mRectIsDirty) {
+        if (mPathIsDirty) {
+            ensureValidRect();
             mPath.reset();
             mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW);
-            mPathIsDirty = mRectIsDirty = false;
+            mPathIsDirty = false;
         }
     }
 
@@ -804,8 +804,8 @@
 
     @Override
     public void setDither(boolean dither) {
-        if (dither != mDither) {
-            mDither = dither;
+        if (dither != mGradientState.mDither) {
+            mGradientState.mDither = dither;
             invalidateSelf();
         }
     }
@@ -829,27 +829,27 @@
         super.onBoundsChange(r);
         mRingPath = null;
         mPathIsDirty = true;
-        mRectIsDirty = true;
+        mGradientIsDirty = true;
     }
 
     @Override
     protected boolean onLevelChange(int level) {
         super.onLevelChange(level);
-        mRectIsDirty = true;
+        mGradientIsDirty = true;
         mPathIsDirty = true;
         invalidateSelf();
         return true;
     }
 
     /**
-     * This checks mRectIsDirty, and if it is true, recomputes both our drawing
+     * This checks mGradientIsDirty, and if it is true, recomputes both our drawing
      * rectangle (mRect) and the gradient itself, since it depends on our
      * rectangle too.
      * @return true if the resulting rectangle is not empty, false otherwise
      */
     private boolean ensureValidRect() {
-        if (mRectIsDirty) {
-            mRectIsDirty = false;
+        if (mGradientIsDirty) {
+            mGradientIsDirty = false;
 
             Rect bounds = getBounds();
             float inset = 0;
@@ -1015,7 +1015,7 @@
         state.mThemeAttrs = a.extractThemeAttrs();
 
         state.mShape = a.getInt(R.styleable.GradientDrawable_shape, state.mShape);
-        mDither = a.getBoolean(R.styleable.GradientDrawable_dither, mDither);
+        state.mDither = a.getBoolean(R.styleable.GradientDrawable_dither, state.mDither);
 
         if (state.mShape == RING) {
             state.mInnerRadius = a.getDimensionPixelSize(
@@ -1459,6 +1459,8 @@
         public float mThicknessRatio = DEFAULT_THICKNESS_RATIO;
         public int mInnerRadius = -1;
         public int mThickness = -1;
+        public boolean mDither = false;
+
         private float mCenterX = 0.5f;
         private float mCenterY = 0.5f;
         private float mGradientRadius = 0.5f;
@@ -1510,6 +1512,7 @@
             mThicknessRatio = state.mThicknessRatio;
             mInnerRadius = state.mInnerRadius;
             mThickness = state.mThickness;
+            mDither = state.mDither;
             mCenterX = state.mCenterX;
             mCenterY = state.mCenterY;
             mGradientRadius = state.mGradientRadius;
@@ -1672,7 +1675,7 @@
 
         initializeWithState(state);
 
-        mRectIsDirty = true;
+        mGradientIsDirty = true;
         mMutated = false;
     }
 
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index beb300d..86765dd 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -396,6 +396,9 @@
                         " for ShapeDrawable " + this);
             }
         }
+
+        // Update local properties.
+        initializeWithState(mShapeState, r);
     }
 
     @Override
@@ -410,12 +413,18 @@
         final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable);
         updateStateFromTypedArray(a);
         a.recycle();
+
+        // Update local properties.
+        initializeWithState(state, t.getResources());
     }
 
     private void updateStateFromTypedArray(TypedArray a) {
         final ShapeState state = mShapeState;
         final Paint paint = state.mPaint;
 
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
         int color = paint.getColor();
         color = a.getColor(R.styleable.ShapeDrawable_color, color);
         paint.setColor(color);
@@ -428,6 +437,16 @@
                 R.styleable.ShapeDrawable_width, state.mIntrinsicWidth));
         setIntrinsicHeight((int) a.getDimension(
                 R.styleable.ShapeDrawable_height, state.mIntrinsicHeight));
+
+        final int tintMode = a.getInt(R.styleable.ShapeDrawable_tintMode, -1);
+        if (tintMode != -1) {
+            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
+        }
+
+        final ColorStateList tint = a.getColorStateList(R.styleable.ShapeDrawable_tint);
+        if (tint != null) {
+            state.mTint = tint;
+        }
     }
 
     private void updateShape() {
@@ -542,6 +561,10 @@
         }
     }
 
+    /**
+     * The one constructor to rule them all. This is called by all public
+     * constructors to set the state and initialize local properties.
+     */
     private ShapeDrawable(ShapeState state, Resources res, Theme theme) {
         if (theme != null && state.canApplyTheme()) {
             mShapeState = new ShapeState(state);
@@ -550,7 +573,16 @@
             mShapeState = state;
         }
 
-        mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode);
+        initializeWithState(state, res);
+    }
+
+    /**
+     * Initializes local dynamic properties from state. This should be called
+     * after significant state changes, e.g. from the One True Constructor and
+     * after inflating or applying a theme.
+     */
+    private void initializeWithState(ShapeState state, Resources res) {
+        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index b4d1fdc..c98f2a1 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -237,34 +237,6 @@
         return PixelFormat.TRANSLUCENT;
     }
 
-    /**
-     * Sets padding for this shape, defined by a Rect object. Define the padding
-     * in the Rect object as: left, top, right, bottom.
-     */
-    public void setPadding(Rect padding) {
-        setPadding(padding.left, padding.top, padding.right, padding.bottom);
-    }
-
-    /**
-     * Sets padding for the shape.
-     *
-     * @param left padding for the left side (in pixels)
-     * @param top padding for the top (in pixels)
-     * @param right padding for the right side (in pixels)
-     * @param bottom padding for the bottom (in pixels)
-     */
-    public void setPadding(int left, int top, int right, int bottom) {
-        if ((left | top | right | bottom) == 0) {
-            mVectorState.mPadding = null;
-        } else {
-            if (mVectorState.mPadding == null) {
-                mVectorState.mPadding = new Rect();
-            }
-            mVectorState.mPadding.set(left, top, right, bottom);
-        }
-        invalidateSelf();
-    }
-
     @Override
     public int getIntrinsicWidth() {
         return (int) mVectorState.mVPathRenderer.mBaseWidth;
@@ -276,23 +248,6 @@
     }
 
     @Override
-    public boolean getPadding(Rect padding) {
-        if (mVectorState.mPadding != null) {
-            padding.set(mVectorState.mPadding);
-            return true;
-        } else {
-            return super.getPadding(padding);
-        }
-    }
-
-    @Override
-    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
-            throws XmlPullParserException, IOException {
-        final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
-        setPathRenderer(p);
-    }
-
-    @Override
     public boolean canApplyTheme() {
         return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
     }
@@ -335,13 +290,44 @@
         return color;
     }
 
-    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
+
+    @Override
+    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
+        final TypedArray a = obtainAttributes(res, theme,  attrs,R.styleable.VectorDrawable);
+        updateStateFromTypedArray(a);
+        a.recycle();
+
+        final VectorDrawableState state = mVectorState;
+        state.mVPathRenderer = inflateInternal(res, parser, attrs, theme);
+
+        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        state.mVPathRenderer.setColorFilter(mTintFilter);
+    }
+
+    private void updateStateFromTypedArray(TypedArray a) {
+        final VectorDrawableState state = mVectorState;
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
+        if (tintMode != -1) {
+            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
+        }
+
+        final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint);
+        if (tint != null) {
+            state.mTint = tint;
+        }
+    }
+
+    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
         final VPathRenderer pathRenderer = new VPathRenderer();
 
         boolean noSizeTag = true;
         boolean noViewportTag = true;
-        boolean noGroupTag = true;
         boolean noPathTag = true;
 
         // Use a stack to help to build the group tree.
@@ -377,7 +363,6 @@
                     if (newChildGroup.getGroupName() != null) {
                         mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup);
                     }
-                    noGroupTag = false;
                 }
             } else if (eventType == XmlPullParser.END_TAG) {
                 final String tagName = parser.getName();
@@ -435,23 +420,19 @@
         }
     }
 
-    private void setPathRenderer(VPathRenderer pathRenderer) {
-        mVectorState.mVPathRenderer = pathRenderer;
-    }
-
     private static class VectorDrawableState extends ConstantState {
+        int[] mThemeAttrs;
         int mChangingConfigurations;
         VPathRenderer mVPathRenderer;
-        Rect mPadding;
         ColorStateList mTint;
         Mode mTintMode;
 
         public VectorDrawableState(VectorDrawableState copy) {
             if (copy != null) {
+                mThemeAttrs = copy.mThemeAttrs;
                 mChangingConfigurations = copy.mChangingConfigurations;
                 // TODO: Make sure the constant state are handled correctly.
                 mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
-                mPadding = new Rect(copy.mPadding);
                 mTint = copy.mTint;
                 mTintMode = copy.mTintMode;
             }
@@ -1019,67 +1000,98 @@
             }
         }
 
-        /* Setters and Getters */
+        /* Setters and Getters, mostly used by animator from AnimatedVectorDrawable. */
+        @SuppressWarnings("unused")
+        public PathParser.PathDataNode[] getPathData() {
+            return mNode;
+        }
+
+        @SuppressWarnings("unused")
+        public void setPathData(PathParser.PathDataNode[] node) {
+            if (!PathParser.canMorph(mNode, node)) {
+                // This should not happen in the middle of animation.
+                mNode = PathParser.deepCopyNodes(node);
+            } else {
+                PathParser.updateNodes(mNode, node);
+            }
+        }
+
+        @SuppressWarnings("unused")
         int getStroke() {
             return mStrokeColor;
         }
 
+        @SuppressWarnings("unused")
         void setStroke(int strokeColor) {
             mStrokeColor = strokeColor;
         }
 
+        @SuppressWarnings("unused")
         float getStrokeWidth() {
             return mStrokeWidth;
         }
 
+        @SuppressWarnings("unused")
         void setStrokeWidth(float strokeWidth) {
             mStrokeWidth = strokeWidth;
         }
 
+        @SuppressWarnings("unused")
         float getStrokeOpacity() {
             return mStrokeOpacity;
         }
 
+        @SuppressWarnings("unused")
         void setStrokeOpacity(float strokeOpacity) {
             mStrokeOpacity = strokeOpacity;
         }
 
+        @SuppressWarnings("unused")
         int getFill() {
             return mFillColor;
         }
 
+        @SuppressWarnings("unused")
         void setFill(int fillColor) {
             mFillColor = fillColor;
         }
 
+        @SuppressWarnings("unused")
         float getFillOpacity() {
             return mFillOpacity;
         }
 
+        @SuppressWarnings("unused")
         void setFillOpacity(float fillOpacity) {
             mFillOpacity = fillOpacity;
         }
 
+        @SuppressWarnings("unused")
         float getTrimPathStart() {
             return mTrimPathStart;
         }
 
+        @SuppressWarnings("unused")
         void setTrimPathStart(float trimPathStart) {
             mTrimPathStart = trimPathStart;
         }
 
+        @SuppressWarnings("unused")
         float getTrimPathEnd() {
             return mTrimPathEnd;
         }
 
+        @SuppressWarnings("unused")
         void setTrimPathEnd(float trimPathEnd) {
             mTrimPathEnd = trimPathEnd;
         }
 
+        @SuppressWarnings("unused")
         float getTrimPathOffset() {
             return mTrimPathOffset;
         }
 
+        @SuppressWarnings("unused")
         void setTrimPathOffset(float trimPathOffset) {
             mTrimPathOffset = trimPathOffset;
         }
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index eff3011..dc6d852 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -160,6 +160,10 @@
     (target->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
 }
 
+uint32_t RenderPropertyAnimator::dirtyMask() {
+    return mPropertyAccess->dirtyMask;
+}
+
 float RenderPropertyAnimator::getValue(RenderNode* target) const {
     return (target->properties().*mPropertyAccess->getter)();
 }
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 203cdff..6cb72c4c 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -61,6 +61,8 @@
     bool isFinished() { return mPlayState == FINISHED; }
     float finalValue() { return mFinalValue; }
 
+    ANDROID_API virtual uint32_t dirtyMask() { return 0; }
+
 protected:
     BaseRenderNodeAnimator(float finalValue);
     virtual ~BaseRenderNodeAnimator();
@@ -112,6 +114,8 @@
 
     ANDROID_API virtual void onAttached(RenderNode* target);
 
+    ANDROID_API virtual uint32_t dirtyMask();
+
 protected:
     virtual float getValue(RenderNode* target) const;
     virtual void setValue(RenderNode* target, float value);
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index f418c9b..e38b532 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -90,8 +90,8 @@
     layers.clear();
 }
 
-void DisplayListData::addChild(DrawDisplayListOp* op) {
-    LOG_ALWAYS_FATAL_IF(!op->renderNode(), "DrawDisplayListOp with no render node!");
+void DisplayListData::addChild(DrawRenderNodeOp* op) {
+    LOG_ALWAYS_FATAL_IF(!op->renderNode(), "DrawRenderNodeOp with no render node!");
 
     mChildren.push(op);
     mReferenceHolders.push(op->renderNode());
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 7b7dc16..bfffbb4 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -61,7 +61,7 @@
 class SaveLayerOp;
 class SaveOp;
 class RestoreToCountOp;
-class DrawDisplayListOp;
+class DrawRenderNodeOp;
 
 /**
  * Holds data used in the playback a tree of DisplayLists.
@@ -133,8 +133,8 @@
         return !displayListOps.size();
     }
 
-    void addChild(DrawDisplayListOp* childOp);
-    const Vector<DrawDisplayListOp*>& children() { return mChildren; }
+    void addChild(DrawRenderNodeOp* childOp);
+    const Vector<DrawRenderNodeOp*>& children() { return mChildren; }
 
     void refProperty(CanvasPropertyPrimitive* prop) {
         mReferenceHolders.push(prop);
@@ -148,7 +148,7 @@
     Vector< sp<VirtualLightRefBase> > mReferenceHolders;
 
     // list of children display lists for quick, non-drawing traversal
-    Vector<DrawDisplayListOp*> mChildren;
+    Vector<DrawRenderNodeOp*> mChildren;
 
     void cleanupResources();
 };
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index d578ef5..811af39 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1465,48 +1465,48 @@
     Functor* mFunctor;
 };
 
-class DrawDisplayListOp : public DrawBoundedOp {
-    friend class RenderNode; // grant DisplayList access to info of child
+class DrawRenderNodeOp : public DrawBoundedOp {
+    friend class RenderNode; // grant RenderNode access to info of child
 public:
-    DrawDisplayListOp(RenderNode* displayList, int flags, const mat4& transformFromParent)
-            : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
-            mDisplayList(displayList), mFlags(flags), mTransformFromParent(transformFromParent) {}
+    DrawRenderNodeOp(RenderNode* renderNode, int flags, const mat4& transformFromParent)
+            : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), 0),
+            mRenderNode(renderNode), mFlags(flags), mTransformFromParent(transformFromParent) {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
             bool useQuickReject) {
-        if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
-            mDisplayList->deferNodeInParent(deferStruct, level + 1);
+        if (mRenderNode && mRenderNode->isRenderable() && !mSkipInOrderDraw) {
+            mRenderNode->defer(deferStruct, level + 1);
         }
     }
     virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
             bool useQuickReject) {
-        if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
-            mDisplayList->replayNodeInParent(replayStruct, level + 1);
+        if (mRenderNode && mRenderNode->isRenderable() && !mSkipInOrderDraw) {
+            mRenderNode->replay(replayStruct, level + 1);
         }
     }
 
-    // NOT USED since replay() is overridden
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return DrawGlInfo::kStatusDone;
+        LOG_ALWAYS_FATAL("should not be called, because replay() is overridden");
+        return 0;
     }
 
     virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
-        if (mDisplayList && (logFlags & kOpLogFlag_Recurse)) {
-            mDisplayList->output(level + 1);
+        OP_LOG("Draw Display List %p, flags %#x", mRenderNode, mFlags);
+        if (mRenderNode && (logFlags & kOpLogFlag_Recurse)) {
+            mRenderNode->output(level + 1);
         }
     }
 
-    virtual const char* name() { return "DrawDisplayList"; }
+    virtual const char* name() { return "DrawRenderNode"; }
 
-    RenderNode* renderNode() { return mDisplayList; }
+    RenderNode* renderNode() { return mRenderNode; }
 
 private:
-    RenderNode* mDisplayList;
+    RenderNode* mRenderNode;
     const int mFlags;
 
     ///////////////////////////
-    // Properties below are used by DisplayList::computeOrderingImpl() and iterate()
+    // Properties below are used by RenderNode::computeOrderingImpl() and issueOperations()
     ///////////////////////////
     /**
      * Records transform vs parent, used for computing total transform without rerunning DL contents
@@ -1514,12 +1514,12 @@
     const mat4 mTransformFromParent;
 
     /**
-     * Holds the transformation between the projection surface ViewGroup and this DisplayList
+     * Holds the transformation between the projection surface ViewGroup and this RenderNode
      * drawing instance. Represents any translations / transformations done within the drawing of
      * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this
      * DisplayList draw instance.
      *
-     * Note: doesn't include any transformation recorded within the DisplayList and its properties.
+     * Note: doesn't include transformation within the RenderNode, or its properties.
      */
     mat4 mTransformFromCompositingAncestor;
     bool mSkipInOrderDraw;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index fc4d40b..b6d3f4b 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -169,18 +169,16 @@
     return StatefulBaseRenderer::clipRegion(region, op);
 }
 
-status_t DisplayListRenderer::drawDisplayList(RenderNode* displayList,
-        Rect& dirty, int32_t flags) {
+status_t DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {
     // dirty is an out parameter and should not be recorded,
     // it matters only when replaying the display list
 
-    if (displayList->stagingProperties().isProjectionReceiver()) {
+    if (renderNode->stagingProperties().isProjectionReceiver()) {
         // use staging property, since recording on UI thread
         mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size();
     }
 
-    DrawDisplayListOp* op = new (alloc()) DrawDisplayListOp(displayList,
-            flags, *currentTransform());
+    DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform());
     addDrawOp(op);
     mDisplayListData->addChild(op);
     return DrawGlInfo::kStatusDone;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 2eaa671..1de656e 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -148,8 +148,7 @@
 // Canvas draw operations - special
 // ----------------------------------------------------------------------------
     virtual status_t drawLayer(Layer* layer, float x, float y);
-    virtual status_t drawDisplayList(RenderNode* displayList, Rect& dirty,
-            int32_t replayFlags);
+    virtual status_t drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags);
 
     // TODO: rename for consistency
     virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index 1f84b86..fc0e8a0 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -112,6 +112,10 @@
     int i1 = (int) ipart;
     int i2 = MathUtils::min(i1 + 1, mSize - 1);
 
+    LOG_ALWAYS_FATAL_IF(i1 < 0 || i2 < 0, "negatives in interpolation!"
+            " i1=%d, i2=%d, input=%f, lutpos=%f, size=%zu, values=%p, ipart=%f, weight=%f",
+            i1, i2, input, lutpos, mSize, mValues, ipart, weight);
+
     float v1 = mValues[i1];
     float v2 = mValues[i2];
 
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 1002e13..b6414e5 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -41,7 +41,7 @@
     colorFilter = NULL;
     deferredUpdateScheduled = false;
     renderer = NULL;
-    displayList = NULL;
+    renderNode = NULL;
     fbo = 0;
     stencil = NULL;
     debugDrawUpdate = false;
@@ -141,10 +141,9 @@
     }
 }
 
-void Layer::updateDeferred(RenderNode* displayList,
-        int left, int top, int right, int bottom) {
+void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom) {
     requireRenderer();
-    this->displayList = displayList;
+    this->renderNode = renderNode;
     const Rect r(left, top, right, bottom);
     dirtyRect.unionWith(r);
     deferredUpdateScheduled = true;
@@ -219,14 +218,14 @@
     renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
             dirtyRect.right, dirtyRect.bottom, !isBlend());
 
-    displayList->computeOrdering();
-    displayList->deferNodeTree(deferredState);
+    renderNode->computeOrdering();
+    renderNode->defer(deferredState, 0);
 
     deferredUpdateScheduled = false;
 }
 
 void Layer::cancelDefer() {
-    displayList = NULL;
+    renderNode = NULL;
     deferredUpdateScheduled = false;
     if (deferredList) {
         delete deferredList;
@@ -246,7 +245,7 @@
         renderer->finish();
 
         dirtyRect.setEmpty();
-        displayList = NULL;
+        renderNode = NULL;
     }
 }
 
@@ -255,14 +254,14 @@
     renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
             !isBlend());
 
-    renderer->drawDisplayList(displayList.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
+    renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
 
     renderer->finish();
 
     dirtyRect.setEmpty();
 
     deferredUpdateScheduled = false;
-    displayList = NULL;
+    renderNode = NULL;
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 49610d5..741f4c3 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -85,8 +85,7 @@
         regionRect.translate(layer.left, layer.top);
     }
 
-    void updateDeferred(RenderNode* displayList,
-            int left, int top, int right, int bottom);
+    void updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom);
 
     inline uint32_t getWidth() const {
         return texture.width;
@@ -297,7 +296,7 @@
      */
     bool deferredUpdateScheduled;
     OpenGLRenderer* renderer;
-    sp<RenderNode> displayList;
+    sp<RenderNode> renderNode;
     Rect dirtyRect;
     bool debugDrawUpdate;
     bool hasDrawnSinceUpdate;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6397478..afb65a6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -474,8 +474,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
-    if (layer->deferredUpdateScheduled && layer->renderer &&
-            layer->displayList.get() && layer->displayList->isRenderable()) {
+    if (layer->deferredUpdateScheduled && layer->renderer
+            && layer->renderNode.get() && layer->renderNode->isRenderable()) {
         ATRACE_CALL();
 
         Rect& dirty = layer->dirtyRect;
@@ -1931,25 +1931,24 @@
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
-status_t OpenGLRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty,
-        int32_t replayFlags) {
+status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
     status_t status;
     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
     // will be performed by the display list itself
-    if (displayList && displayList->isRenderable()) {
+    if (renderNode && renderNode->isRenderable()) {
         // compute 3d ordering
-        displayList->computeOrdering();
+        renderNode->computeOrdering();
         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
             status = startFrame();
             ReplayStateStruct replayStruct(*this, dirty, replayFlags);
-            displayList->replayNodeTree(replayStruct);
+            renderNode->replay(replayStruct, 0);
             return status | replayStruct.mDrawGlStatus;
         }
 
         bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
         DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
-        displayList->deferNodeTree(deferStruct);
+        renderNode->defer(deferStruct, 0);
 
         flushLayers();
         status = startFrame();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 346a65c..066b267 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -158,7 +158,7 @@
     int saveLayerDeferred(float left, float top, float right, float bottom,
             const SkPaint* paint, int flags);
 
-    virtual status_t drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
+    virtual status_t drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
     virtual status_t drawLayer(Layer* layer, float x, float y);
     virtual status_t drawBitmap(const SkBitmap* bitmap, float left, float top,
             const SkPaint* paint);
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 9dd5aa5..97eb583 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -104,8 +104,7 @@
 }
 
 static void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
-    bitmap.setConfig(SkBitmap::kA8_Config, width, height);
-    bitmap.allocPixels();
+    bitmap.allocPixels(SkImageInfo::MakeA8(width, height));
     bitmap.eraseColor(0);
 }
 
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 3d93383..e8f2dd2 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -15,7 +15,7 @@
  */
 
 #define ATRACE_TAG ATRACE_TAG_VIEW
-#define LOG_TAG "RenderNode"
+#define LOG_TAG "OpenGLRenderer"
 
 #include "RenderNode.h"
 
@@ -323,8 +323,8 @@
             info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
         }
         for (size_t i = 0; i < subtree->children().size(); i++) {
-            DrawDisplayListOp* op = subtree->children()[i];
-            RenderNode* childNode = op->mDisplayList;
+            DrawRenderNodeOp* op = subtree->children()[i];
+            RenderNode* childNode = op->mRenderNode;
             info.damageAccumulator->pushTransform(&op->mTransformFromParent);
             childNode->prepareTreeImpl(info);
             info.damageAccumulator->popTransform();
@@ -455,16 +455,16 @@
     // transform properties are applied correctly to top level children
     if (mDisplayListData == NULL) return;
     for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
-        DrawDisplayListOp* childOp = mDisplayListData->children()[i];
-        childOp->mDisplayList->computeOrderingImpl(childOp,
+        DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
+        childOp->mRenderNode->computeOrderingImpl(childOp,
                 properties().getOutline().getPath(), &mProjectedNodes, &mat4::identity());
     }
 }
 
 void RenderNode::computeOrderingImpl(
-        DrawDisplayListOp* opState,
+        DrawRenderNodeOp* opState,
         const SkPath* outlineOfProjectionSurface,
-        Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
+        Vector<DrawRenderNodeOp*>* compositedChildrenOfProjectionSurface,
         const mat4* transformFromProjectionSurface) {
     mProjectedNodes.clear();
     if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return;
@@ -488,11 +488,11 @@
         const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
         bool haveAppliedPropertiesToProjection = false;
         for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
-            DrawDisplayListOp* childOp = mDisplayListData->children()[i];
-            RenderNode* child = childOp->mDisplayList;
+            DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
+            RenderNode* child = childOp->mRenderNode;
 
             const SkPath* projectionOutline = NULL;
-            Vector<DrawDisplayListOp*>* projectionChildren = NULL;
+            Vector<DrawRenderNodeOp*>* projectionChildren = NULL;
             const mat4* projectionTransform = NULL;
             if (isProjectionReceiver && !child->properties().getProjectBackwards()) {
                 // if receiving projections, collect projecting descendent
@@ -536,15 +536,7 @@
     const int mLevel;
 };
 
-void RenderNode::deferNodeTree(DeferStateStruct& deferStruct) {
-    DeferOperationHandler handler(deferStruct, 0);
-    if (MathUtils::isPositive(properties().getZ())) {
-        issueDrawShadowOperation(Matrix4::identity(), handler);
-    }
-    issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
-}
-
-void RenderNode::deferNodeInParent(DeferStateStruct& deferStruct, const int level) {
+void RenderNode::defer(DeferStateStruct& deferStruct, const int level) {
     DeferOperationHandler handler(deferStruct, level);
     issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler);
 }
@@ -574,29 +566,21 @@
     const int mLevel;
 };
 
-void RenderNode::replayNodeTree(ReplayStateStruct& replayStruct) {
-    ReplayOperationHandler handler(replayStruct, 0);
-    if (MathUtils::isPositive(properties().getZ())) {
-        issueDrawShadowOperation(Matrix4::identity(), handler);
-    }
-    issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
-}
-
-void RenderNode::replayNodeInParent(ReplayStateStruct& replayStruct, const int level) {
+void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) {
     ReplayOperationHandler handler(replayStruct, level);
     issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler);
 }
 
-void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
+void RenderNode::buildZSortedChildList(Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) {
     if (mDisplayListData == NULL || mDisplayListData->children().size() == 0) return;
 
     for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
-        DrawDisplayListOp* childOp = mDisplayListData->children()[i];
-        RenderNode* child = childOp->mDisplayList;
+        DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
+        RenderNode* child = childOp->mRenderNode;
         float childZ = child->properties().getZ();
 
         if (!MathUtils::isZero(childZ)) {
-            zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp));
+            zTranslatedNodes.add(ZDrawRenderNodeOpPair(childZ, childOp));
             childOp->mSkipInOrderDraw = true;
         } else if (!child->properties().getProjectBackwards()) {
             // regular, in order drawing DisplayList
@@ -641,10 +625,40 @@
     handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
 }
 
+template <class T>
+int RenderNode::issueOperationsOfNegZChildren(
+        const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes,
+        OpenGLRenderer& renderer, T& handler) {
+    if (zTranslatedNodes.isEmpty()) return -1;
+
+    // create a save around the body of the ViewGroup's draw method, so that
+    // matrix/clip methods don't affect composited children
+    int shadowSaveCount = renderer.getSaveCount();
+    handler(new (handler.allocator()) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
+            PROPERTY_SAVECOUNT, properties().getClipToBounds());
+
+    issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+    return shadowSaveCount;
+}
+
+template <class T>
+void RenderNode::issueOperationsOfPosZChildren(int shadowRestoreTo,
+        const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes,
+        OpenGLRenderer& renderer, T& handler) {
+    if (zTranslatedNodes.isEmpty()) return;
+
+    LOG_ALWAYS_FATAL_IF(shadowRestoreTo < 0, "invalid save to restore to");
+    handler(new (handler.allocator()) RestoreToCountOp(shadowRestoreTo),
+            PROPERTY_SAVECOUNT, properties().getClipToBounds());
+    renderer.setOverrideLayerAlpha(1.0f);
+
+    issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+}
+
 #define SHADOW_DELTA 0.1f
 
 template <class T>
-void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
+void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes,
         ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) {
     const int size = zTranslatedNodes.size();
     if (size == 0
@@ -679,8 +693,8 @@
     float lastCasterZ = 0.0f;
     while (shadowIndex < endIndex || drawIndex < endIndex) {
         if (shadowIndex < endIndex) {
-            DrawDisplayListOp* casterOp = zTranslatedNodes[shadowIndex].value;
-            RenderNode* caster = casterOp->mDisplayList;
+            DrawRenderNodeOp* casterOp = zTranslatedNodes[shadowIndex].value;
+            RenderNode* caster = casterOp->mRenderNode;
             const float casterZ = zTranslatedNodes[shadowIndex].key;
             // attempt to render the shadow if the caster about to be drawn is its caster,
             // OR if its caster's Z value is similar to the previous potential caster
@@ -697,8 +711,8 @@
         // since it modifies the renderer's matrix
         int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
 
-        DrawDisplayListOp* childOp = zTranslatedNodes[drawIndex].value;
-        RenderNode* child = childOp->mDisplayList;
+        DrawRenderNodeOp* childOp = zTranslatedNodes[drawIndex].value;
+        RenderNode* child = childOp->mRenderNode;
 
         renderer.concatMatrix(childOp->mTransformFromParent);
         childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
@@ -714,8 +728,6 @@
 void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) {
     DISPLAY_LIST_LOGD("%*s%d projected children:", (handler.level() + 1) * 2, "", mProjectedNodes.size());
     const SkPath* projectionReceiverOutline = properties().getOutline().getPath();
-    bool maskProjecteesWithPath = projectionReceiverOutline != NULL
-            && !projectionReceiverOutline->isRect(NULL);
     int restoreTo = renderer.getSaveCount();
 
     // If the projection reciever has an outline, we mask each of the projected rendernodes to it
@@ -736,7 +748,7 @@
             SaveLayerOp* op = new (alloc) SaveLayerOp(
                     outlineBounds.left(), outlineBounds.top(),
                     outlineBounds.right(), outlineBounds.bottom(),
-                    255, SkCanvas::kARGB_ClipLayer_SaveFlag);
+                    255, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag | SkCanvas::kARGB_ClipLayer_SaveFlag);
             op->setMask(projectionReceiverOutline);
             handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
 
@@ -749,7 +761,7 @@
 
     // draw projected nodes
     for (size_t i = 0; i < mProjectedNodes.size(); i++) {
-        DrawDisplayListOp* childOp = mProjectedNodes[i];
+        DrawRenderNodeOp* childOp = mProjectedNodes[i];
 
         // matrix save, concat, and restore can be done safely without allocating operations
         int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
@@ -821,11 +833,11 @@
             handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
                     renderer.getSaveCount() - 1, properties().getClipToBounds());
         } else {
-            Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
+            Vector<ZDrawRenderNodeOpPair> zTranslatedNodes;
             buildZSortedChildList(zTranslatedNodes);
 
             // for 3d root, draw children with negative z values
-            issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+            int shadowRestoreTo = issueOperationsOfNegZChildren(zTranslatedNodes, renderer, handler);
 
             DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
             const int saveCountOffset = renderer.getSaveCount() - 1;
@@ -833,9 +845,9 @@
             for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
                 DisplayListOp *op = mDisplayListData->displayListOps[i];
 
-    #if DEBUG_DISPLAY_LIST
+#if DEBUG_DISPLAY_LIST
                 op->output(level + 1);
-    #endif
+#endif
                 logBuffer.writeCommand(level, op->name());
                 handler(op, saveCountOffset, properties().getClipToBounds());
 
@@ -845,7 +857,7 @@
             }
 
             // for 3d root, draw children with positive z values
-            issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+            issueOperationsOfPosZChildren(shadowRestoreTo, zTranslatedNodes, renderer, handler);
         }
     }
 
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index b2fe849..2fa6078 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -67,7 +67,7 @@
 class SaveLayerOp;
 class SaveOp;
 class RestoreToCountOp;
-class DrawDisplayListOp;
+class DrawRenderNodeOp;
 
 /**
  * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
@@ -113,11 +113,8 @@
 
     void computeOrdering();
 
-    void deferNodeTree(DeferStateStruct& deferStruct);
-    void deferNodeInParent(DeferStateStruct& deferStruct, const int level);
-
-    void replayNodeTree(ReplayStateStruct& replayStruct);
-    void replayNodeInParent(ReplayStateStruct& replayStruct, const int level);
+    void defer(DeferStateStruct& deferStruct, const int level);
+    void replay(ReplayStateStruct& replayStruct, const int level);
 
     ANDROID_API void output(uint32_t level = 1);
     ANDROID_API int getDebugSize();
@@ -189,6 +186,8 @@
     // UI thread only!
     ANDROID_API void removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
         mStagingAnimators.erase(animator);
+        // Force a sync of the staging property value
+        mDirtyPropertyFields |= animator->dirtyMask();
         mNeedsAnimatorsSync = true;
     }
 
@@ -196,9 +195,9 @@
     virtual void damageSelf(TreeInfo& info);
 
 private:
-    typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair;
+    typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
 
-    static size_t findNonNegativeIndex(const Vector<ZDrawDisplayListOpPair>& nodes) {
+    static size_t findNonNegativeIndex(const Vector<ZDrawRenderNodeOpPair>& nodes) {
         for (size_t i = 0; i < nodes.size(); i++) {
             if (nodes[i].key >= 0.0f) return i;
         }
@@ -212,21 +211,29 @@
 
     void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false);
 
-    void computeOrderingImpl(DrawDisplayListOp* opState,
+    void computeOrderingImpl(DrawRenderNodeOp* opState,
             const SkPath* outlineOfProjectionSurface,
-            Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
+            Vector<DrawRenderNodeOp*>* compositedChildrenOfProjectionSurface,
             const mat4* transformFromProjectionSurface);
 
     template <class T>
     inline void setViewProperties(OpenGLRenderer& renderer, T& handler);
 
-    void buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes);
+    void buildZSortedChildList(Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes);
 
     template<class T>
     inline void issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler);
 
     template <class T>
-    inline void issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes,
+    inline int issueOperationsOfNegZChildren(
+            const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes,
+            OpenGLRenderer& renderer, T& handler);
+    template <class T>
+    inline void issueOperationsOfPosZChildren(int shadowRestoreTo,
+            const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes,
+            OpenGLRenderer& renderer, T& handler);
+    template <class T>
+    inline void issueOperationsOf3dChildren(const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes,
             ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler);
 
     template <class T>
@@ -234,7 +241,7 @@
 
     /**
      * Issue the RenderNode's operations into a handler, recursing for subtrees through
-     * DrawDisplayListOp's defer() or replay() methods
+     * DrawRenderNodeOp's defer() or replay() methods
      */
     template <class T>
     inline void issueOperations(OpenGLRenderer& renderer, T& handler);
@@ -285,7 +292,7 @@
      */
 
     // for projection surfaces, contains a list of all children items
-    Vector<DrawDisplayListOp*> mProjectedNodes;
+    Vector<DrawRenderNodeOp*> mProjectedNodes;
 }; // class RenderNode
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 320895c..d68b932 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -233,7 +233,7 @@
 // Canvas draw operations - special
 // ----------------------------------------------------------------------------
     virtual status_t drawLayer(Layer* layer, float x, float y) = 0;
-    virtual status_t drawDisplayList(RenderNode* displayList, Rect& dirty,
+    virtual status_t drawRenderNode(RenderNode* renderNode, Rect& dirty,
             int32_t replayFlags) = 0;
 
     // TODO: rename for consistency
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 1001cae0..9212d0a 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -333,8 +333,7 @@
 void TextureCache::uploadLoFiTexture(bool resize, const SkBitmap* bitmap,
         uint32_t width, uint32_t height) {
     SkBitmap rgbaBitmap;
-    rgbaBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0, bitmap->alphaType());
-    rgbaBitmap.allocPixels();
+    rgbaBitmap.allocPixels(SkImageInfo::MakeN32(width, height, bitmap->alphaType()));
     rgbaBitmap.eraseColor(0);
 
     SkCanvas canvas(rgbaBitmap);
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index dc1951b..eab98102 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -469,7 +469,7 @@
 
 void CanvasContext::draw() {
     LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
-            "drawDisplayList called on a context with no canvas or surface!");
+            "drawRenderNode called on a context with no canvas or surface!");
 
     profiler().markPlaybackStart();
 
@@ -496,7 +496,7 @@
     }
 
     Rect outBounds;
-    status |= mCanvas->drawDisplayList(mRootRenderNode.get(), outBounds);
+    status |= mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
 
     profiler().draw(mCanvas);
 
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index 3f6ccc9..063383b 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -206,9 +206,8 @@
             } else {
                 SkBitmap surfaceBitmap;
                 ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
-                surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config,
-                        outBuffer.width, outBuffer.height, bpr);
-                surfaceBitmap.setPixels(outBuffer.bits);
+                surfaceBitmap.installPixels(SkImageInfo::MakeN32Premul(outBuffer.width, outBuffer.height),
+                                            outBuffer.bits, bpr);
 
                 SkCanvas surfaceCanvas(surfaceBitmap);
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d35225a..fb19242 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1254,11 +1254,6 @@
      * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
      * <p>Even if a SCO connection is established, the following restrictions apply on audio
      * output streams so that they can be routed to SCO headset:
-     * <p>NOTE: up to and including API version
-     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
-     * voice call to the bluetooth headset.
-     * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
-     * connection is established.
      * <ul>
      *   <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
      *   <li> the format must be mono </li>
@@ -1274,6 +1269,11 @@
      * it will be ignored. Similarly, if a call is received or sent while an application
      * is using the SCO connection, the connection will be lost for the application and NOT
      * returned automatically when the call ends.
+     * <p>NOTE: up to and including API version
+     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
+     * voice call to the bluetooth headset.
+     * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
+     * connection is established.
      * @see #stopBluetoothSco()
      * @see #ACTION_SCO_AUDIO_STATE_UPDATED
      */
@@ -1287,13 +1287,38 @@
     }
 
     /**
+     * Start bluetooth SCO audio connection in virtual call mode.
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
+     * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
+     * Telephony and communication applications (VoIP, Video Chat) should preferably select
+     * virtual call mode.
+     * Applications using voice input for search or commands should first try raw audio connection
+     * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
+     * failure.
+     * @see #startBluetoothSco()
+     * @see #stopBluetoothSco()
+     * @see #ACTION_SCO_AUDIO_STATE_UPDATED
+     */
+    public void startBluetoothScoVirtualCall() {
+        IAudioService service = getService();
+        try {
+            service.startBluetoothScoVirtualCall(mICallBack);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in startBluetoothScoVirtualCall", e);
+        }
+    }
+
+    /**
      * Stop bluetooth SCO audio connection.
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
      * <p>This method must be called by applications having requested the use of
-     * bluetooth SCO audio with {@link #startBluetoothSco()}
-     * when finished with the SCO connection or if connection fails.
+     * bluetooth SCO audio with {@link #startBluetoothSco()} or
+     * {@link #startBluetoothScoVirtualCall()} when finished with the SCO connection or
+     * if connection fails.
      * @see #startBluetoothSco()
+     * @see #startBluetoothScoVirtualCall()
      */
     public void stopBluetoothSco(){
         IAudioService service = getService();
@@ -2169,48 +2194,8 @@
             Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
             return;
         }
-        IAudioService service = getService();
-        try {
-            // pi != null, this is currently still needed to support across
-            // reboot launching of the last app.
-            service.registerMediaButtonIntent(pi, eventReceiver,
-                    eventReceiver == null ? mToken : null);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
-        }
         MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-        helper.addMediaButtonListener(pi, mContext);
-    }
-
-    /**
-     * @hide
-     * Used internally by telephony package to register an intent receiver for ACTION_MEDIA_BUTTON.
-     * @param eventReceiver the component that will receive the media button key events,
-     *          no-op if eventReceiver is null
-     */
-    public void registerMediaButtonEventReceiverForCalls(ComponentName eventReceiver) {
-        if (eventReceiver == null) {
-            return;
-        }
-        IAudioService service = getService();
-        try {
-            // eventReceiver != null
-            service.registerMediaButtonEventReceiverForCalls(eventReceiver);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in registerMediaButtonEventReceiverForCalls", e);
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public void unregisterMediaButtonEventReceiverForCalls() {
-        IAudioService service = getService();
-        try {
-            service.unregisterMediaButtonEventReceiverForCalls();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in unregisterMediaButtonEventReceiverForCalls", e);
-        }
+        helper.addMediaButtonListener(pi, eventReceiver, mContext);
     }
 
     /**
@@ -2247,12 +2232,6 @@
      * @hide
      */
     public void unregisterMediaButtonIntent(PendingIntent pi) {
-        IAudioService service = getService();
-        try {
-            service.unregisterMediaButtonIntent(pi);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
-        }
         MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
         helper.removeMediaButtonListener(pi);
     }
@@ -2418,46 +2397,6 @@
     }
 
     /**
-     * @hide
-     * Request the user of a RemoteControlClient to seek to the given playback position.
-     * @param generationId the RemoteControlClient generation counter for which this request is
-     *         issued. Requests for an older generation than current one will be ignored.
-     * @param timeMs the time in ms to seek to, must be positive.
-     */
-    public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
-        if (timeMs < 0) {
-            return;
-        }
-        IAudioService service = getService();
-        try {
-            service.setRemoteControlClientPlaybackPosition(generationId, timeMs);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setRccPlaybackPosition("+ generationId + ", "
-                    + timeMs + ")", e);
-        }
-    }
-
-    /**
-     * @hide
-     * Notify the user of a RemoteControlClient that it should update its metadata with the
-     * new value for the given key.
-     * @param generationId the RemoteControlClient generation counter for which this request is
-     *         issued. Requests for an older generation than current one will be ignored.
-     * @param key the metadata key for which a new value exists
-     * @param value the new metadata value
-     */
-    public void updateRemoteControlClientMetadata(int generationId, int key,
-            Rating value) {
-        IAudioService service = getService();
-        try {
-            service.updateRemoteControlClientMetadata(generationId, key, value);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in updateRemoteControlClientMetadata("+ generationId + ", "
-                    + key +", " + value + ")", e);
-        }
-    }
-
-    /**
      *  @hide
      *  Reload audio settings. This method is called by Settings backup
      *  agent when audio settings are restored and causes the AudioService
@@ -2873,12 +2812,9 @@
      * @hide
      */
     public int getRemoteStreamVolume() {
-        try {
-            return getService().getRemoteStreamVolume();
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error getting remote stream volume", e);
-            return 0;
-        }
+        // TODO STOPSHIP switch callers to use media sessions instead
+        Log.e(TAG, "Need to implement new Remote Volume!");
+        return 0;
     }
 
     /**
@@ -2886,12 +2822,9 @@
      * @hide
      */
     public int getRemoteStreamMaxVolume() {
-        try {
-            return getService().getRemoteStreamMaxVolume();
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error getting remote stream max volume", e);
-            return 0;
-        }
+        // TODO STOPSHIP switch callers to use media sessions instead
+        Log.e(TAG, "Need to implement new Remote Volume!");
+        return 0;
     }
 
     /**
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 48479a4..0c224a6 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -2056,7 +2056,19 @@
     }
 
     /** @see AudioManager#startBluetoothSco() */
-    public void startBluetoothSco(IBinder cb, int targetSdkVersion){
+    public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
+        int scoAudioMode =
+                (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
+                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
+        startBluetoothScoInt(cb, scoAudioMode);
+    }
+
+    /** @see AudioManager#startBluetoothScoVirtualCall() */
+    public void startBluetoothScoVirtualCall(IBinder cb) {
+        startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
+    }
+
+    void startBluetoothScoInt(IBinder cb, int scoAudioMode){
         if (!checkAudioSettingsPermission("startBluetoothSco()") ||
                 !mSystemReady) {
             return;
@@ -2068,7 +2080,7 @@
         // The caller identity must be cleared after getScoClient() because it is needed if a new
         // client is created.
         final long ident = Binder.clearCallingIdentity();
-        client.incCount(targetSdkVersion);
+        client.incCount(scoAudioMode);
         Binder.restoreCallingIdentity(ident);
     }
 
@@ -2114,9 +2126,9 @@
             }
         }
 
-        public void incCount(int targetSdkVersion) {
+        public void incCount(int scoAudioMode) {
             synchronized(mScoClients) {
-                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion);
+                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
                 if (mStartcount == 0) {
                     try {
                         mCb.linkToDeath(this, 0);
@@ -2186,7 +2198,7 @@
             }
         }
 
-        private void requestScoState(int state, int targetSdkVersion) {
+        private void requestScoState(int state, int scoAudioMode) {
             checkScoAudioState();
             if (totalCount() == 0) {
                 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
@@ -2201,9 +2213,7 @@
                                 (mScoAudioState == SCO_STATE_INACTIVE ||
                                  mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
                             if (mScoAudioState == SCO_STATE_INACTIVE) {
-                                mScoAudioMode =
-                                        (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
-                                                SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
+                                mScoAudioMode = scoAudioMode;
                                 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
                                     boolean status;
                                     if (mScoAudioMode == SCO_MODE_RAW) {
@@ -4402,68 +4412,12 @@
         mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
     }
 
-    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
-        mMediaFocusControl.registerMediaButtonEventReceiverForCalls(c);
-    }
-
-    public void unregisterMediaButtonEventReceiverForCalls() {
-        mMediaFocusControl.unregisterMediaButtonEventReceiverForCalls();
-    }
-
-    public void registerMediaButtonIntent(PendingIntent pi, ComponentName c, IBinder token) {
-        mMediaFocusControl.registerMediaButtonIntent(pi, c, token);
-    }
-
-    public void unregisterMediaButtonIntent(PendingIntent pi) {
-        mMediaFocusControl.unregisterMediaButtonIntent(pi);
-    }
-
-    public int registerRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient, String callingPckg) {
-        return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg);
-    }
-
-    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient) {
-        mMediaFocusControl.unregisterRemoteControlClient(mediaIntent, rcClient);
-    }
-
-    public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
-        mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
-    }
-
-    public void updateRemoteControlClientMetadata(int generationId, int key, Rating value) {
-        mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value);
-    }
-
-    public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
-        mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo);
-    }
-
-    @Override
-    public int getRemoteStreamVolume() {
-        return mMediaFocusControl.getRemoteStreamVolume();
-    }
-
-    @Override
-    public int getRemoteStreamMaxVolume() {
-        return mMediaFocusControl.getRemoteStreamMaxVolume();
-    }
-
     @Override
     public void setRemoteStreamVolume(int index) {
         enforceSelfOrSystemUI("set the remote stream volume");
         mMediaFocusControl.setRemoteStreamVolume(index);
     }
 
-    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
-        mMediaFocusControl.setPlaybackStateForRcc(rccId, state, timeMs, speed);
-    }
-
-    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
-        mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value);
-    }
-
     //==========================================================================================
     // Audio Focus
     //==========================================================================================
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 169631e..4dcdd19 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -122,12 +122,6 @@
 
     int getCurrentAudioFocus();
 
-           void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c, IBinder token);
-    oneway void unregisterMediaButtonIntent(in PendingIntent pi);
-
-    oneway void registerMediaButtonEventReceiverForCalls(in ComponentName c);
-    oneway void unregisterMediaButtonEventReceiverForCalls();
-
     /**
      * Register an IRemoteControlDisplay.
      * Success of registration is subject to a check on
@@ -180,43 +174,9 @@
      */
     oneway void remoteControlDisplayWantsPlaybackPositionSync(in IRemoteControlDisplay rcd,
             boolean wantsSync);
-    /**
-     * Request the user of a RemoteControlClient to seek to the given playback position.
-     * @param generationId the RemoteControlClient generation counter for which this request is
-     *         issued. Requests for an older generation than current one will be ignored.
-     * @param timeMs the time in ms to seek to, must be positive.
-     */
-     void setRemoteControlClientPlaybackPosition(int generationId, long timeMs);
-     /**
-      * Notify the user of a RemoteControlClient that it should update its metadata with the
-      * new value for the given key.
-      * @param generationId the RemoteControlClient generation counter for which this request is
-      *         issued. Requests for an older generation than current one will be ignored.
-      * @param key the metadata key for which a new value exists
-      * @param value the new metadata value
-      */
-     void updateRemoteControlClientMetadata(int generationId, int key, in Rating value);
-
-    /**
-     * Do not use directly, use instead
-     *     {@link android.media.AudioManager#registerRemoteControlClient(RemoteControlClient)}
-     */
-    int registerRemoteControlClient(in PendingIntent mediaIntent,
-            in IRemoteControlClient rcClient, in String callingPackageName);
-    /**
-     * Do not use directly, use instead
-     *     {@link android.media.AudioManager#unregisterRemoteControlClient(RemoteControlClient)}
-     */
-    oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
-            in IRemoteControlClient rcClient);
-
-    oneway void setPlaybackInfoForRcc(int rccId, int what, int value);
-    void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed);
-           int  getRemoteStreamMaxVolume();
-           int  getRemoteStreamVolume();
-    oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo);
 
     void startBluetoothSco(IBinder cb, int targetSdkVersion);
+    void startBluetoothScoVirtualCall(IBinder cb);
     void stopBluetoothSco(IBinder cb);
 
     void forceVolumeControlStream(int streamType, IBinder cb);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 440653a..6559bc5 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -181,6 +181,27 @@
     }
 
     /**
+     * Thrown when an unrecoverable failure occurs during a MediaDrm operation.
+     * Extends java.lang.IllegalStateException with the addition of an error
+     * code that may be useful in diagnosing the failure.
+     */
+    public static final class MediaDrmStateException extends java.lang.IllegalStateException {
+        private final int mErrorCode;
+
+        public MediaDrmStateException(int errorCode, String detailMessage) {
+            super(detailMessage);
+            mErrorCode = errorCode;
+        }
+
+        /**
+         * Retrieve the associated error code
+         */
+        public int getErrorCode() {
+            return mErrorCode;
+        }
+    }
+
+    /**
      * Register a callback to be invoked when an event occurs
      *
      * @param listener the callback that will be run
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 1c73c05..a4a7c4e 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -379,32 +379,11 @@
                     onReevaluateRemote();
                     break;
 
-                case MSG_RCC_NEW_PLAYBACK_INFO:
-                    onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */,
-                            ((Integer)msg.obj).intValue() /* value */);
-                    break;
-
                 case MSG_RCC_NEW_VOLUME_OBS:
                     onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
                             (IRemoteVolumeObserver)msg.obj /* rvo */);
                     break;
 
-                case MSG_RCC_NEW_PLAYBACK_STATE:
-                    onNewPlaybackStateForRcc(msg.arg1 /* rccId */,
-                            msg.arg2 /* state */,
-                            (PlayerRecord.RccPlaybackState)msg.obj /* newState */);
-                    break;
-
-                case MSG_RCC_SEEK_REQUEST:
-                    onSetRemoteControlClientPlaybackPosition(
-                            msg.arg1 /* generationId */, ((Long)msg.obj).longValue() /* timeMs */);
-                    break;
-
-                case MSG_RCC_UPDATE_METADATA:
-                    onUpdateRemoteControlClientMetadata(msg.arg1 /*genId*/, msg.arg2 /*key*/,
-                            (Rating) msg.obj /* value */);
-                    break;
-
                 case MSG_RCDISPLAY_INIT_INFO:
                     // msg.obj is guaranteed to be non null
                     onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
@@ -2003,217 +1982,6 @@
         }
     }
 
-    protected void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
-        // ignore position change requests if invalid generation ID
-        synchronized(mPRStack) {
-            synchronized(mCurrentRcLock) {
-                if (mCurrentRcClientGen != generationId) {
-                    return;
-                }
-            }
-        }
-        // discard any unprocessed seek request in the message queue, and replace with latest
-        sendMsg(mEventHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */,
-                0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */);
-    }
-
-    private void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
-        if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId +
-                ", timeMs=" + timeMs + ")");
-        synchronized(mPRStack) {
-            synchronized(mCurrentRcLock) {
-                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) {
-                    // tell the current client to seek to the requested location
-                    try {
-                        mCurrentRcClient.seekTo(generationId, timeMs);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Current valid remote client is dead: "+e);
-                        mCurrentRcClient = null;
-                    }
-                }
-            }
-        }
-    }
-
-    protected void updateRemoteControlClientMetadata(int genId, int key, Rating value) {
-        sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA, SENDMSG_QUEUE,
-                genId /* arg1 */, key /* arg2 */, value /* obj */, 0 /* delay */);
-    }
-
-    private void onUpdateRemoteControlClientMetadata(int genId, int key, Rating value) {
-        if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadata(genId=" + genId +
-                ", what=" + key + ",rating=" + value + ")");
-        synchronized(mPRStack) {
-            synchronized(mCurrentRcLock) {
-                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == genId)) {
-                    try {
-                        switch (key) {
-                            case MediaMetadataEditor.RATING_KEY_BY_USER:
-                                mCurrentRcClient.updateMetadata(genId, key, value);
-                                break;
-                            default:
-                                Log.e(TAG, "unhandled metadata key " + key + " update for RCC "
-                                        + genId);
-                                break;
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Current valid remote client is dead", e);
-                        mCurrentRcClient = null;
-                    }
-                }
-            }
-        }
-    }
-
-    protected void setPlaybackInfoForRcc(int rccId, int what, int value) {
-        sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
-                rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);
-    }
-
-    // handler for MSG_RCC_NEW_PLAYBACK_INFO
-    private void onNewPlaybackInfoForRcc(int rccId, int key, int value) {
-        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId +
-                ", what=" + key + ",val=" + value + ")");
-        synchronized(mPRStack) {
-            // iterating from top of stack as playback information changes are more likely
-            //   on entries at the top of the remote control stack
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    if (prse.getRccId() == rccId) {
-                        switch (key) {
-                            case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE:
-                                prse.mPlaybackType = value;
-                                postReevaluateRemote();
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_VOLUME:
-                                prse.mPlaybackVolume = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemote.mVolume = value;
-                                        mVolumeController.postHasNewRemotePlaybackInfo();
-                                    }
-                                }
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX:
-                                prse.mPlaybackVolumeMax = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemote.mVolumeMax = value;
-                                        mVolumeController.postHasNewRemotePlaybackInfo();
-                                    }
-                                }
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING:
-                                prse.mPlaybackVolumeHandling = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemote.mVolumeHandling = value;
-                                        mVolumeController.postHasNewRemotePlaybackInfo();
-                                    }
-                                }
-                                break;
-                            case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
-                                prse.mPlaybackStream = value;
-                                break;
-                            default:
-                                Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
-                                break;
-                        }
-                        return;
-                    }
-                }//for
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index mPRStack on onNewPlaybackInfoForRcc, lock error? ", e);
-            }
-        }
-    }
-
-    protected void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
-        sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE,
-                rccId /* arg1 */, state /* arg2 */,
-                new PlayerRecord.RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */);
-    }
-
-    private void onNewPlaybackStateForRcc(int rccId, int state,
-            PlayerRecord.RccPlaybackState newState) {
-        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
-                + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
-        synchronized(mPRStack) {
-            if (mPRStack.empty()) {
-                return;
-            }
-            PlayerRecord oldTopPrse = mPRStack.lastElement(); // top of the stack before any changes
-            PlayerRecord prse = null;
-            int lastPlayingIndex = mPRStack.size();
-            int inStackIndex = -1;
-            try {
-                // go through the stack from the top to figure out who's playing, and the position
-                // of this RemoteControlClient (note that it may not be in the stack)
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    prse = mPRStack.elementAt(index);
-                    if (prse.getRccId() == rccId) {
-                        inStackIndex = index;
-                        prse.mPlaybackState = newState;
-                    }
-                    if (prse.isPlaybackActive()) {
-                        lastPlayingIndex = index;
-                    }
-                }
-
-                if (inStackIndex != -1) {
-                    // is in the stack
-                    prse = mPRStack.elementAt(inStackIndex);
-                    synchronized (mMainRemote) {
-                        if (rccId == mMainRemote.mRccId) {
-                            mMainRemoteIsActive = isPlaystateActive(state);
-                            postReevaluateRemote();
-                        }
-                    }
-                    if (mPRStack.size() > 1) { // no need to remove and add if stack contains only 1
-                        // remove it from its old location in the stack
-                        mPRStack.removeElementAt(inStackIndex);
-                        if (prse.isPlaybackActive()) {
-                            // and put it at the top
-                            mPRStack.push(prse);
-                        } else {
-                            // and put it after the ones with active playback
-                            if (inStackIndex > lastPlayingIndex) {
-                                mPRStack.add(lastPlayingIndex, prse);
-                            } else {
-                                mPRStack.add(lastPlayingIndex - 1, prse);
-                            }
-                        }
-                    }
-
-                    if (oldTopPrse != mPRStack.lastElement()) {
-                        // the top of the stack changed:
-                        final ComponentName target =
-                                mPRStack.lastElement().getMediaButtonReceiver();
-                        if (target != null) {
-                            // post message to persist the default media button receiver
-                            mEventHandler.sendMessage( mEventHandler.obtainMessage(
-                                    MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
-                        }
-                        // reevaluate the display
-                        checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification or bad index
-                Log.e(TAG, "Wrong index (inStack=" + inStackIndex + " lastPlaying=" + lastPlayingIndex
-                        + " size=" + mPRStack.size()
-                        + "accessing PlayerRecord stack in onNewPlaybackStateForRcc", e);
-            }
-        }
-    }
-
-    protected void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
-        sendMsg(mEventHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE,
-                rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */);
-    }
-
     // handler for MSG_RCC_NEW_VOLUME_OBS
     private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
         synchronized(mPRStack) {
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index ddd5b72..3336694 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -29,7 +29,6 @@
 import android.hardware.display.WifiDisplay;
 import android.hardware.display.WifiDisplayStatus;
 import android.media.session.MediaSession;
-import android.media.session.RemoteVolumeProvider;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
@@ -2204,10 +2203,10 @@
                 return;
             }
             if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
-                int volumeControl = RemoteVolumeProvider.VOLUME_CONTROL_FIXED;
+                int volumeControl = VolumeProvider.VOLUME_CONTROL_FIXED;
                 switch (mVolumeHandling) {
                     case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE:
-                        volumeControl = RemoteVolumeProvider.VOLUME_CONTROL_ABSOLUTE;
+                        volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
                         break;
                     case RemoteControlClient.PLAYBACK_VOLUME_FIXED:
                     default:
@@ -2226,7 +2225,7 @@
             }
         }
 
-        class SessionVolumeProvider extends RemoteVolumeProvider {
+        class SessionVolumeProvider extends VolumeProvider {
 
             public SessionVolumeProvider(int volumeControl, int maxVolume) {
                 super(volumeControl, maxVolume);
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 76c7299..be96398 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -361,18 +361,10 @@
         if (timeMs < 0) {
             throw new IllegalArgumentException("illegal negative time value");
         }
-        if (USE_SESSIONS) {
-            synchronized (mInfoLock) {
-                if (mCurrentSession != null) {
-                    mCurrentSession.getTransportControls().seekTo(timeMs);
-                }
+        synchronized (mInfoLock) {
+            if (mCurrentSession != null) {
+                mCurrentSession.getTransportControls().seekTo(timeMs);
             }
-        } else {
-            final int genId;
-            synchronized (mGenLock) {
-                genId = mClientGenerationIdCurrent;
-            }
-            mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
         }
         return true;
     }
@@ -534,34 +526,15 @@
             if (!mMetadataChanged) {
                 return;
             }
-            if (USE_SESSIONS) {
-                synchronized (mInfoLock) {
-                    if (mCurrentSession != null) {
-                        if (mEditorMetadata.containsKey(
-                                String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
-                            Rating rating = (Rating) getObject(
-                                    MediaMetadataEditor.RATING_KEY_BY_USER, null);
-                            if (rating != null) {
-                                mCurrentSession.getTransportControls().setRating(rating);
-                            }
-                        }
-                    }
-                }
-            } else {
-                final int genId;
-                synchronized(mGenLock) {
-                    genId = mClientGenerationIdCurrent;
-                }
-                synchronized(mInfoLock) {
+            synchronized (mInfoLock) {
+                if (mCurrentSession != null) {
                     if (mEditorMetadata.containsKey(
                             String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
                         Rating rating = (Rating) getObject(
                                 MediaMetadataEditor.RATING_KEY_BY_USER, null);
-                        mAudioManager.updateRemoteControlClientMetadata(genId,
-                              MediaMetadataEditor.RATING_KEY_BY_USER,
-                              rating);
-                    } else {
-                        Log.e(TAG, "no metadata to apply");
+                        if (rating != null) {
+                            mCurrentSession.getTransportControls().setRating(rating);
+                        }
                     }
                 }
             }
diff --git a/media/java/android/media/session/RemoteVolumeProvider.java b/media/java/android/media/VolumeProvider.java
similarity index 92%
rename from media/java/android/media/session/RemoteVolumeProvider.java
rename to media/java/android/media/VolumeProvider.java
index 606b1d7..7d93b40 100644
--- a/media/java/android/media/session/RemoteVolumeProvider.java
+++ b/media/java/android/media/VolumeProvider.java
@@ -13,8 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.media.session;
+package android.media;
 
+import android.media.session.MediaSession;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -24,8 +25,8 @@
  * You can set a volume provider on a session by calling
  * {@link MediaSession#setPlaybackToRemote}.
  */
-public abstract class RemoteVolumeProvider {
-    private static final String TAG = "RemoteVolumeProvider";
+public abstract class VolumeProvider {
+    private static final String TAG = "VolumeProvider";
 
     /**
      * The volume is fixed and can not be modified. Requests to change volume
@@ -60,7 +61,7 @@
      *            this provider.
      * @param maxVolume The maximum allowed volume.
      */
-    public RemoteVolumeProvider(int volumeControl, int maxVolume) {
+    public VolumeProvider(int volumeControl, int maxVolume) {
         mControlType = volumeControl;
         mMaxVolume = maxVolume;
     }
@@ -117,7 +118,7 @@
     /**
      * @hide
      */
-    void setSession(MediaSession session) {
+    public void setSession(MediaSession session) {
         mSession = session;
     }
 }
\ No newline at end of file
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 1cfc5bc..5bc0de4 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -15,6 +15,7 @@
 
 package android.media.session;
 
+import android.content.ComponentName;
 import android.media.MediaMetadata;
 import android.media.session.ISessionController;
 import android.media.session.RouteOptions;
@@ -33,6 +34,7 @@
     ISessionController getController();
     void setFlags(int flags);
     void setActive(boolean active);
+    void setMediaButtonReceiver(in ComponentName mbr);
     void destroy();
 
     // These commands are for setting up and communicating with routes
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index f0cd785..b4c11f6 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -20,6 +20,7 @@
 import android.media.Rating;
 import android.media.session.ISessionControllerCallback;
 import android.media.session.MediaSessionInfo;
+import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.ResultReceiver;
@@ -38,6 +39,9 @@
     void showRoutePicker();
     MediaSessionInfo getSessionInfo();
     long getFlags();
+    ParcelableVolumeInfo getVolumeAttributes();
+    void adjustVolumeBy(int delta, int flags);
+    void setVolumeTo(int value, int flags);
 
     // These commands are for the TransportController
     void play();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 87a43e4..84dad25 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -18,6 +18,7 @@
 
 import android.media.MediaMetadata;
 import android.media.Rating;
+import android.media.VolumeProvider;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -183,6 +184,23 @@
     }
 
     /**
+     * Get the current volume info for this session.
+     *
+     * @return The current volume info or null.
+     */
+    public VolumeInfo getVolumeInfo() {
+        try {
+            ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes();
+            return new VolumeInfo(result.volumeType, result.audioStream, result.controlType,
+                    result.maxVolume, result.currentVolume);
+
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getVolumeInfo.", e);
+        }
+        return null;
+    }
+
+    /**
      * Adds a callback to receive updates from the Session. Updates will be
      * posted on the caller's thread.
      *
@@ -509,6 +527,85 @@
         }
     }
 
+    /**
+     * Holds information about the way volume is handled for this session.
+     */
+    public static final class VolumeInfo {
+        private final int mVolumeType;
+        private final int mAudioStream;
+        private final int mVolumeControl;
+        private final int mMaxVolume;
+        private final int mCurrentVolume;
+
+        /**
+         * @hide
+         */
+        public VolumeInfo(int type, int stream, int control, int max, int current) {
+            mVolumeType = type;
+            mAudioStream = stream;
+            mVolumeControl = control;
+            mMaxVolume = max;
+            mCurrentVolume = current;
+        }
+
+        /**
+         * Get the type of volume handling, either local or remote. One of:
+         * <ul>
+         * <li>{@link MediaSession#VOLUME_TYPE_LOCAL}</li>
+         * <li>{@link MediaSession#VOLUME_TYPE_REMOTE}</li>
+         * </ul>
+         *
+         * @return The type of volume handling this session is using.
+         */
+        public int getVolumeType() {
+            return mVolumeType;
+        }
+
+        /**
+         * Get the stream this is currently controlling volume on. When the volume
+         * type is {@link MediaSession#VOLUME_TYPE_REMOTE} this value does not
+         * have meaning and should be ignored.
+         *
+         * @return The stream this session is playing on.
+         */
+        public int getAudioStream() {
+            return mAudioStream;
+        }
+
+        /**
+         * Get the type of volume control that can be used. One of:
+         * <ul>
+         * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li>
+         * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li>
+         * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li>
+         * </ul>
+         *
+         * @return The type of volume control that may be used with this
+         *         session.
+         */
+        public int getVolumeControl() {
+            return mVolumeControl;
+        }
+
+        /**
+         * Get the maximum volume that may be set for this session.
+         *
+         * @return The maximum allowed volume where this session is playing.
+         */
+        public int getMaxVolume() {
+            return mMaxVolume;
+        }
+
+        /**
+         * Get the current volume for this session.
+         *
+         * @return The current volume where this session is playing.
+         */
+        public int getCurrentVolume() {
+            return mCurrentVolume;
+        }
+    }
+
     private final static class CallbackStub extends ISessionControllerCallback.Stub {
         private final WeakReference<MediaController> mController;
 
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 4ba1351..406b1c3 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -19,10 +19,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.media.AudioManager;
 import android.media.MediaMetadata;
 import android.media.Rating;
+import android.media.VolumeProvider;
 import android.media.session.ISessionController;
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
@@ -125,18 +127,12 @@
     public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5;
 
     /**
-     * The session uses local playback. Used for configuring volume handling
-     * with the system.
-     *
-     * @hide
+     * The session uses local playback.
      */
     public static final int VOLUME_TYPE_LOCAL = 1;
 
     /**
-     * The session uses remote playback. Used for configuring volume handling
-     * with the system.
-     *
-     * @hide
+     * The session uses remote playback.
      */
     public static final int VOLUME_TYPE_REMOTE = 2;
 
@@ -155,7 +151,7 @@
             = new ArrayMap<String, RouteInterface.EventListener>();
 
     private Route mRoute;
-    private RemoteVolumeProvider mVolumeProvider;
+    private VolumeProvider mVolumeProvider;
 
     private boolean mActive = false;;
 
@@ -232,6 +228,21 @@
     }
 
     /**
+     * Set a media button event receiver component to use to restart playback
+     * after an app has been stopped.
+     *
+     * @param mbr The receiver component to send the media button event to.
+     * @hide
+     */
+    public void setMediaButtonReceiver(ComponentName mbr) {
+        try {
+            mBinder.setMediaButtonReceiver(mbr);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
+        }
+    }
+
+    /**
      * Set any flags for the session.
      *
      * @param flags The flags to set for this session.
@@ -272,7 +283,7 @@
      * @param volumeProvider The provider that will handle volume changes. May
      *            not be null.
      */
-    public void setPlaybackToRemote(RemoteVolumeProvider volumeProvider) {
+    public void setPlaybackToRemote(VolumeProvider volumeProvider) {
         if (volumeProvider == null) {
             throw new IllegalArgumentException("volumeProvider may not be null!");
         }
@@ -524,12 +535,12 @@
     }
 
     /**
-     * Notify the system that the remove volume changed.
+     * Notify the system that the remote volume changed.
      *
      * @param provider The provider that is handling volume changes.
      * @hide
      */
-    void notifyRemoteVolumeChanged(RemoteVolumeProvider provider) {
+    public void notifyRemoteVolumeChanged(VolumeProvider provider) {
         if (provider == null || provider != mVolumeProvider) {
             Log.w(TAG, "Received update from stale volume provider");
             return;
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 801844f..838b857 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -18,6 +18,7 @@
 
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.media.MediaMetadata;
@@ -214,7 +215,7 @@
         }
     }
 
-    public void addMediaButtonListener(PendingIntent pi,
+    public void addMediaButtonListener(PendingIntent pi, ComponentName mbrComponent,
             Context context) {
         if (pi == null) {
             Log.w(TAG, "Pending intent was null, can't addMediaButtonListener.");
@@ -238,6 +239,7 @@
 
         holder.mMediaButtonReceiver = new MediaButtonReceiver(pi, context);
         holder.mSession.addCallback(holder.mMediaButtonReceiver, mHandler);
+        holder.mSession.setMediaButtonReceiver(mbrComponent);
         if (DEBUG) {
             Log.d(TAG, "addMediaButtonListener added " + pi);
         }
diff --git a/media/java/android/media/session/ParcelableVolumeInfo.aidl b/media/java/android/media/session/ParcelableVolumeInfo.aidl
new file mode 100644
index 0000000..c4250f0
--- /dev/null
+++ b/media/java/android/media/session/ParcelableVolumeInfo.aidl
@@ -0,0 +1,18 @@
+/* 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.media.session;
+
+parcelable ParcelableVolumeInfo;
diff --git a/media/java/android/media/session/ParcelableVolumeInfo.java b/media/java/android/media/session/ParcelableVolumeInfo.java
new file mode 100644
index 0000000..166ccd3
--- /dev/null
+++ b/media/java/android/media/session/ParcelableVolumeInfo.java
@@ -0,0 +1,78 @@
+/* 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.media.session;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Convenience class for passing information about the audio configuration of a
+ * session. The public implementation is {@link MediaController.VolumeInfo}.
+ *
+ * @hide
+ */
+public class ParcelableVolumeInfo implements Parcelable {
+    public int volumeType;
+    public int audioStream;
+    public int controlType;
+    public int maxVolume;
+    public int currentVolume;
+
+    public ParcelableVolumeInfo(int volumeType, int audioStream, int controlType, int maxVolume,
+            int currentVolume) {
+        this.volumeType = volumeType;
+        this.audioStream = audioStream;
+        this.controlType = controlType;
+        this.maxVolume = maxVolume;
+        this.currentVolume = currentVolume;
+    }
+
+    public ParcelableVolumeInfo(Parcel from) {
+        volumeType = from.readInt();
+        audioStream = from.readInt();
+        controlType = from.readInt();
+        maxVolume = from.readInt();
+        currentVolume = from.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(volumeType);
+        dest.writeInt(audioStream);
+        dest.writeInt(controlType);
+        dest.writeInt(maxVolume);
+        dest.writeInt(currentVolume);
+    }
+
+
+    public static final Parcelable.Creator<ParcelableVolumeInfo> CREATOR
+            = new Parcelable.Creator<ParcelableVolumeInfo>() {
+        @Override
+        public ParcelableVolumeInfo createFromParcel(Parcel in) {
+            return new ParcelableVolumeInfo(in);
+        }
+
+        @Override
+        public ParcelableVolumeInfo[] newArray(int size) {
+            return new ParcelableVolumeInfo[size];
+        }
+    };
+}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 4fbd2a4..5f27b16 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -110,6 +110,11 @@
     jfieldID certificateData;
 };
 
+struct StateExceptionFields {
+    jmethodID init;
+    jclass classId;
+};
+
 struct fields_t {
     jfieldID context;
     jmethodID post_event;
@@ -121,6 +126,7 @@
     IteratorFields iterator;
     EntryFields entry;
     CertificateFields certificate;
+    StateExceptionFields stateException;
     jclass certificateClassId;
     jclass hashmapClassId;
     jclass arraylistClassId;
@@ -212,6 +218,14 @@
     }
 }
 
+static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
+    ALOGE("Illegal state exception: %s (%d)", msg, err);
+
+    jobject exception = env->NewObject(gFields.stateException.classId,
+            gFields.stateException.init, static_cast<int>(err),
+            env->NewStringUTF(msg));
+    env->Throw(static_cast<jthrowable>(exception));
+}
 
 static bool throwExceptionAsNecessary(
         JNIEnv *env, status_t err, const char *msg = NULL) {
@@ -275,8 +289,7 @@
                 msg = errbuf.string();
             }
         }
-        ALOGE("Illegal state exception: %s", msg);
-        jniThrowException(env, "java/lang/IllegalStateException", msg);
+        throwStateException(env, msg, err);
         return true;
     }
     return false;
@@ -608,6 +621,10 @@
 
     FIND_CLASS(clazz, "java/util/ArrayList");
     gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+    FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
+    GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
+    gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
 }
 
 static void android_media_MediaDrm_native_setup(
diff --git a/media/tests/ScoAudioTest/res/layout/scoaudiotest.xml b/media/tests/ScoAudioTest/res/layout/scoaudiotest.xml
index b769a0c..acb7767 100644
--- a/media/tests/ScoAudioTest/res/layout/scoaudiotest.xml
+++ b/media/tests/ScoAudioTest/res/layout/scoaudiotest.xml
@@ -125,6 +125,11 @@
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:text="@string/audiomanagertwo" />
+        <CheckBox
+            android:id="@+id/useVirtualCallCheckBox"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/useVirtualCallCheckText" />
             
     </LinearLayout>
 
diff --git a/media/tests/ScoAudioTest/res/values/strings.xml b/media/tests/ScoAudioTest/res/values/strings.xml
index c3ff6d5..b0284e2 100644
--- a/media/tests/ScoAudioTest/res/values/strings.xml
+++ b/media/tests/ScoAudioTest/res/values/strings.xml
@@ -10,5 +10,5 @@
     <string name="tts_speak">Speak TTS</string>
     <string name="tts_to_file">TTS to file</string>
     <string name="audiomanagertwo">Use different AudioManager for starting SCO</string>
-    
+    <string name="useVirtualCallCheckText">Use Virtual Call</string>
 </resources>
diff --git a/media/tests/ScoAudioTest/src/com/android/scoaudiotest/ScoAudioTest.java b/media/tests/ScoAudioTest/src/com/android/scoaudiotest/ScoAudioTest.java
index 0304640..7e21876 100644
--- a/media/tests/ScoAudioTest/src/com/android/scoaudiotest/ScoAudioTest.java
+++ b/media/tests/ScoAudioTest/src/com/android/scoaudiotest/ScoAudioTest.java
@@ -207,16 +207,25 @@
             if (mForceScoOn != isChecked) {
                 mForceScoOn = isChecked;
                 AudioManager mngr = mAudioManager;
+                boolean useVirtualCall = false;
                 CheckBox box = (CheckBox) findViewById(R.id.useSecondAudioManager);
                 if (box.isChecked()) {
                     Log.i(TAG, "Using 2nd audio manager");
                     mngr = mAudioManager2;
                 }
+                box = (CheckBox) findViewById(R.id.useVirtualCallCheckBox);
+                useVirtualCall = box.isChecked();
 
                 if (mForceScoOn) {
-                    Log.e(TAG, "startBluetoothSco() IN");
-                    mngr.startBluetoothSco();
-                    Log.e(TAG, "startBluetoothSco() OUT");
+                    if (useVirtualCall) {
+                        Log.e(TAG, "startBluetoothScoVirtualCall() IN");
+                        mngr.startBluetoothScoVirtualCall();
+                        Log.e(TAG, "startBluetoothScoVirtualCall() OUT");
+                    } else {
+                        Log.e(TAG, "startBluetoothSco() IN");
+                        mngr.startBluetoothSco();
+                        Log.e(TAG, "startBluetoothSco() OUT");
+                    }
                 } else {
                     Log.e(TAG, "stopBluetoothSco() IN");
                     mngr.stopBluetoothSco();
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index a4d292a..229bfdb 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -105,7 +105,7 @@
     meta->findInt32(kKeyWidth, &width);
     meta->findInt32(kKeyHeight, &height);
     configBitmapSize(
-            bm, SkColorTypeToBitmapConfig(getPrefColorType(k32Bit_SrcDepth, false)),
+            bm, getPrefColorType(k32Bit_SrcDepth, false),
             width, height);
 
     // mode == DecodeBounds
@@ -169,15 +169,9 @@
     return true;
 }
 
-void OmxJpegImageDecoder::configBitmapSize(SkBitmap* bm, SkBitmap::Config pref,
+void OmxJpegImageDecoder::configBitmapSize(SkBitmap* bm, SkColorType pref,
         int width, int height) {
-    bm->setConfig(getColorSpaceConfig(pref), width, height, 0, kOpaque_SkAlphaType);
-}
-
-SkBitmap::Config OmxJpegImageDecoder::getColorSpaceConfig(
-        SkBitmap::Config pref) {
-
-    // Set the color space to ARGB_8888 for now
+    // Set the color space to ARGB_8888 for now (ignoring pref)
     // because of limitation in hardware support.
-    return SkBitmap::kARGB_8888_Config;
+    bm->setInfo(SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType));
 }
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h b/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
index e431e72..e487245 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
@@ -49,9 +49,7 @@
     sp<MediaSource> getDecoder(OMXClient* client, const sp<MediaSource>& source);
     bool decodeSource(sp<MediaSource> decoder, const sp<MediaSource>& source,
             SkBitmap* bm);
-    void configBitmapSize(SkBitmap* bm, SkBitmap::Config pref, int width,
-            int height);
-    SkBitmap::Config getColorSpaceConfig(SkBitmap::Config pref);
+    void configBitmapSize(SkBitmap* bm, SkColorType, int width, int height);
 
     OMXClient mClient;
 };
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index d2bf30c..ab18271 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -71,6 +71,7 @@
     private AppWidgetHost mAppWidgetHost;
     private AppWidgetManager mAppWidgetManager;
     private KeyguardWidgetPager mAppWidgetContainer;
+    // TODO remove transport control references, these don't exist anymore
     private KeyguardTransportControlView mTransportControl;
     private int mAppWidgetToShow;
 
@@ -235,36 +236,6 @@
                 mKeyguardMultiUserSelectorView.finalizeActiveUserView(true);
             }
         }
-        @Override
-        public void onMusicClientIdChanged(
-                int clientGeneration, boolean clearing, android.app.PendingIntent intent) {
-            // Set transport state to invisible until we know music is playing (below)
-            if (DEBUGXPORT && (mClientGeneration != clientGeneration || clearing)) {
-                Log.v(TAG, (clearing ? "hide" : "show") + " transport, gen:" + clientGeneration);
-            }
-            mClientGeneration = clientGeneration;
-            final int newState = (clearing ? TRANSPORT_GONE
-                    : (mTransportState == TRANSPORT_VISIBLE ?
-                    TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
-            if (newState != mTransportState) {
-                mTransportState = newState;
-                if (DEBUGXPORT) Log.v(TAG, "update widget: transport state changed");
-                KeyguardHostView.this.post(mSwitchPageRunnable);
-            }
-        }
-        @Override
-        public void onMusicPlaybackStateChanged(int playbackState, long eventTime) {
-            if (DEBUGXPORT) Log.v(TAG, "music state changed: " + playbackState);
-            if (mTransportState != TRANSPORT_GONE) {
-                final int newState = (isMusicPlaying(playbackState) ?
-                        TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE);
-                if (newState != mTransportState) {
-                    mTransportState = newState;
-                    if (DEBUGXPORT) Log.v(TAG, "update widget: play state changed");
-                    KeyguardHostView.this.post(mSwitchPageRunnable);
-                }
-            }
-        }
     };
 
     private static final boolean isMusicPlaying(int playbackState) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index 7918755..38316ff 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -166,6 +166,11 @@
         return info;
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
     // This is an optimization to ensure we only recompute the patterns when the inputs change.
     private static final class Patterns {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 668e1ef..bf34705 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -91,8 +91,6 @@
     private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312;
     protected static final int MSG_BOOT_COMPLETED = 313;
     private static final int MSG_USER_SWITCH_COMPLETE = 314;
-    private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
-    protected static final int MSG_SET_PLAYBACK_STATE = 316;
     protected static final int MSG_USER_INFO_CHANGED = 317;
     protected static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
     private static final int MSG_SCREEN_TURNED_ON = 319;
@@ -184,12 +182,6 @@
                 case MSG_BOOT_COMPLETED:
                     handleBootCompleted();
                     break;
-                case MSG_SET_CURRENT_CLIENT_ID:
-                    handleSetGenerationId(msg.arg1, msg.arg2 != 0, (PendingIntent) msg.obj);
-                    break;
-                case MSG_SET_PLAYBACK_STATE:
-                    handleSetPlaybackState(msg.arg1, msg.arg2, (Long) msg.obj);
-                    break;
                 case MSG_USER_INFO_CHANGED:
                     handleUserInfoChanged(msg.arg1);
                     break;
@@ -206,8 +198,6 @@
         }
     };
 
-    private AudioManager mAudioManager;
-
     private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
 
     @Override
@@ -257,49 +247,6 @@
 
     private DisplayClientState mDisplayClientState = new DisplayClientState();
 
-    /**
-     * This currently implements the bare minimum required to enable showing and hiding
-     * KeyguardTransportControl.  There's a lot of client state to maintain which is why
-     * KeyguardTransportControl maintains an independent connection while it's showing.
-     */
-    private final IRemoteControlDisplay.Stub mRemoteControlDisplay =
-                new IRemoteControlDisplay.Stub() {
-
-        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
-                long currentPosMs, float speed) {
-            Message msg = mHandler.obtainMessage(MSG_SET_PLAYBACK_STATE,
-                    generationId, state, stateChangeTimeMs);
-            mHandler.sendMessage(msg);
-        }
-
-        public void setMetadata(int generationId, Bundle metadata) {
-
-        }
-
-        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
-
-        }
-
-        public void setArtwork(int generationId, Bitmap bitmap) {
-
-        }
-
-        public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
-
-        }
-
-        public void setEnabled(boolean enabled) {
-            // no-op: this RemoteControlDisplay is not subject to being disabled.
-        }
-
-        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
-                boolean clearing) throws RemoteException {
-            Message msg = mHandler.obtainMessage(MSG_SET_CURRENT_CLIENT_ID,
-                        clientGeneration, (clearing ? 1 : 0), mediaIntent);
-            mHandler.sendMessage(msg);
-        }
-    };
-
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
 
         public void onReceive(Context context, Intent intent) {
@@ -501,38 +448,6 @@
         }
     }
 
-    protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) {
-        mDisplayClientState.clientGeneration = clientGeneration;
-        mDisplayClientState.clearing = clearing;
-        mDisplayClientState.intent = p;
-        if (DEBUG)
-            Log.v(TAG, "handleSetGenerationId(g=" + clientGeneration + ", clear=" + clearing + ")");
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onMusicClientIdChanged(clientGeneration, clearing, p);
-            }
-        }
-    }
-
-    protected void handleSetPlaybackState(int generationId, int playbackState, long eventTime) {
-        if (DEBUG)
-            Log.v(TAG, "handleSetPlaybackState(gen=" + generationId
-                + ", state=" + playbackState + ", t=" + eventTime + ")");
-        mDisplayClientState.playbackState = playbackState;
-        mDisplayClientState.playbackEventTime = eventTime;
-        if (generationId == mDisplayClientState.clientGeneration) {
-            for (int i = 0; i < mCallbacks.size(); i++) {
-                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-                if (cb != null) {
-                    cb.onMusicPlaybackStateChanged(playbackState, eventTime);
-                }
-            }
-        } else {
-            Log.w(TAG, "Ignoring generation id " + generationId + " because it's not current");
-        }
-    }
-
     private void handleUserInfoChanged(int userId) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -694,8 +609,6 @@
     protected void handleBootCompleted() {
         if (mBootCompleted) return;
         mBootCompleted = true;
-        mAudioManager = new AudioManager(mContext);
-        mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -1013,12 +926,6 @@
         callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
         callback.onClockVisibilityChanged();
         callback.onSimStateChanged(mSimState);
-        callback.onMusicClientIdChanged(
-                mDisplayClientState.clientGeneration,
-                mDisplayClientState.clearing,
-                mDisplayClientState.intent);
-        callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState,
-                mDisplayClientState.playbackEventTime);
     }
 
     public void sendKeyguardVisibilityChanged(boolean showing) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index bcdf18f..01600d2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -144,18 +144,6 @@
     public void onBootCompleted() { }
 
     /**
-     * Called when audio client attaches or detaches from AudioManager.
-     */
-    public void onMusicClientIdChanged(int clientGeneration, boolean clearing, PendingIntent intent) { }
-
-    /**
-     * Called when the audio playback state changes.
-     * @param playbackState
-     * @param eventTime
-     */
-    public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { }
-
-    /**
      * Called when the emergency call button is pressed.
      */
     void onEmergencyCallAction() { }
diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml
index a7e8514..4a4c1c1 100644
--- a/packages/SystemUI/res/drawable/ic_account_circle.xml
+++ b/packages/SystemUI/res/drawable/ic_account_circle.xml
@@ -22,7 +22,13 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"/>
 
+    <group
+        android:scaleX="1.2"
+        android:scaleY="1.2"
+        android:pivotX="12.0"
+        android:pivotY="12.0">
     <path
         android:fill="#FFFFFFFF"
         android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
+    </group>
 </vector>
diff --git a/packages/SystemUI/res/drawable/notification_scrim.xml b/packages/SystemUI/res/drawable/notification_scrim.xml
new file mode 100644
index 0000000..ff7e31f1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_scrim.xml
@@ -0,0 +1,22 @@
+<?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
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#34000000" />
+    <corners android:radius="@*android:dimen/notification_material_rounded_rect_radius" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher.xml b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
new file mode 100644
index 0000000..5648065
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
@@ -0,0 +1,25 @@
+<?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
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/keyguard_user_switcher"
+        android:orientation="vertical"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:gravity="end"
+        android:visibility="gone"
+        android:paddingTop="4dp">
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
new file mode 100644
index 0000000..691a80e
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
@@ -0,0 +1,40 @@
+<?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
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:sysui="http://schemas.android.com/apk/res-auto"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="8dp"
+        android:layout_marginEnd="8dp"
+        android:gravity="center_vertical"
+        android:clickable="true"
+        android:background="@drawable/ripple_drawable">
+    <TextView android:id="@+id/name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="16dp"
+            android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.UserName"
+            />
+    <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/picture"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:contentDescription="@null"
+            sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness"
+            sysui:activeFrameColor="@color/current_user_border_color" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index cde83bf..b54ba1a 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -24,6 +24,7 @@
     android:id="@+id/notification_panel"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="@android:color/transparent"
     >
 
     <include
@@ -91,6 +92,14 @@
 
     <include layout="@layout/status_bar_expanded_header" />
 
+    <ViewStub
+        android:id="@+id/keyguard_user_switcher"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
+        android:layout_gravity="end"
+        android:layout="@layout/keyguard_user_switcher" />
+
     <include
         layout="@layout/keyguard_bottom_area"
         android:visibility="gone" />
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 353368b..2e4c0ef 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -73,9 +73,9 @@
         android:layout_width="wrap_content"
         android:layout_height="@dimen/status_bar_header_height"
         android:layout_toStartOf="@id/multi_user_switch"
-        android:layout_marginEnd="2dp"
+        android:layout_alignWithParentIfMissing="true"
         android:layout_marginStart="16dp"
-        />
+        android:paddingEnd="2dp" />
 
     <TextView
         android:id="@+id/header_charging_info"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index c442f79..f0f50e1 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -49,4 +49,10 @@
         android:layout_width="120dp"
         android:layout_height="wrap_content"
         />
+
+    <com.android.systemui.statusbar.NotificationScrimView
+        android:id="@+id/scrim_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
 </com.android.systemui.statusbar.NotificationOverflowContainer>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 5fabd3e..7663d54 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -48,4 +48,9 @@
         android:padding="2dp"
         />
 
+    <com.android.systemui.statusbar.NotificationScrimView
+        android:id="@+id/scrim_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
 </com.android.systemui.statusbar.ExpandableNotificationRow>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 47581a9..9f4c364 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -32,4 +32,7 @@
     <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
          card. -->
     <integer name="keyguard_max_notification_count">5</integer>
+
+    <!-- Set to true to enable the user switcher on the keyguard. -->
+    <bool name="config_keyguardUserSwitcher">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index c453618..8473d96 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -54,5 +54,10 @@
         <enum name="horizontal" value="0" />
         <enum name="vertical" value="1" />
     </attr>
+    <declare-styleable name="UserAvatarView">
+        <attr name="frameWidth" format="dimension" />
+        <attr name="activeFrameColor" format="color" />
+        <attr name="frameColor" />
+    </declare-styleable>
 </resources>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 3bd8689..4e38da6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -60,6 +60,9 @@
 
     <color name="keyguard_affordance">#ffffffff</color>
 
+    <!-- The color of the circle around the primary user in the user switcher -->
+    <color name="current_user_border_color">@color/primary_color</color>
+
     <!-- Our material color palette (deep teal) -->
     <color name="primary_color">#ff7fcac3</color>
     <color name="background_color_1">#ff384248</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c64a182..c1f971a 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -109,7 +109,7 @@
     <integer name="heads_up_sensitivity_delay">700</integer>
 
     <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
-    <integer name="recents_task_bar_dismiss_delay_seconds">3</integer>
+    <integer name="recents_task_bar_dismiss_delay_seconds">1</integer>
     <!-- The min animation duration for animating views that are currently visible. -->
     <integer name="recents_filter_animate_current_views_duration">250</integer>
     <!-- The min animation duration for animating views that are newly visible. -->
@@ -154,5 +154,8 @@
          Notification.tickerText across the status bar for what seems like an
          eternity. -->
     <bool name="enable_ticker">false</bool>
+
+    <!-- Set to true to enable the user switcher on the keyguard. -->
+    <bool name="config_keyguardUserSwitcher">false</bool>
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bbcc9c1..36c1994 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -320,6 +320,9 @@
          device. -->
     <dimen name="unlock_move_distance">75dp</dimen>
 
+    <!-- Distance after which the scrim starts fading in when dragging down the quick settings -->
+    <dimen name="notification_scrim_wait_distance">100dp</dimen>
+
     <!-- Move distance for the unlock hint animation on the lockscreen -->
     <dimen name="hint_move_distance">75dp</dimen>
 
@@ -332,4 +335,11 @@
 
     <!-- end margin for multi user switch in expanded quick settings -->
     <dimen name="multi_user_switch_expanded_margin">8dp</dimen>
+
+    <!-- end margin for system icons if multi user switch is hidden -->
+    <dimen name="system_icons_switcher_hidden_expanded_margin">16dp</dimen>
+
+    <!-- The thickness of the colored border around the current user. -->
+    <dimen name="keyguard_user_switcher_border_thickness">2dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index c117eba..e5d5b03 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -100,6 +100,13 @@
     <style name="TextAppearance.StatusBar.Expanded.Network.EmergencyOnly">
     </style>
 
+    <style name="TextAppearance.StatusBar.Expanded.UserSwitcher">
+        <item name="android:textSize">16sp</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#ffffff</item>
+    </style>
+    <style name="TextAppearance.StatusBar.Expanded.UserSwitcher.UserName" />
+
     <style name="TextAppearance" />
     <style name="TextAppearance.QuickSettings" />
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 9ea346b..2d90e1a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -577,23 +577,33 @@
     public void onEnterAnimationTriggered() {
         // Fade in the scrims
         if (mConfig.hasStatusBarScrim() && mConfig.shouldAnimateStatusBarScrim()) {
-            mStatusBarScrimView.setVisibility(View.VISIBLE);
             mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight());
             mStatusBarScrimView.animate()
                     .translationY(0)
                     .setStartDelay(mConfig.taskBarEnterAnimDelay)
                     .setDuration(mConfig.navBarScrimEnterDuration)
                     .setInterpolator(mConfig.quintOutInterpolator)
+                    .withStartAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            mStatusBarScrimView.setVisibility(View.VISIBLE);
+                        }
+                    })
                     .start();
         }
         if (mConfig.hasNavBarScrim() && mConfig.shouldAnimateNavBarScrim()) {
-            mNavBarScrimView.setVisibility(View.VISIBLE);
             mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
             mNavBarScrimView.animate()
                     .translationY(0)
                     .setStartDelay(mConfig.taskBarEnterAnimDelay)
                     .setDuration(mConfig.navBarScrimEnterDuration)
                     .setInterpolator(mConfig.quintOutInterpolator)
+                    .withStartAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            mNavBarScrimView.setVisibility(View.VISIBLE);
+                        }
+                    })
                     .start();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java
index 2f89e6d2..d525546 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 
+import java.util.ArrayList;
+
 /**
  * A ref counted trigger that does some logic when the count is first incremented, or last
  * decremented.  Not thread safe as it's not currently needed.
@@ -26,8 +28,8 @@
 
     Context mContext;
     int mCount;
-    Runnable mFirstIncRunnable;
-    Runnable mLastDecRunnable;
+    ArrayList<Runnable> mFirstIncRunnables = new ArrayList<Runnable>();
+    ArrayList<Runnable> mLastDecRunnables = new ArrayList<Runnable>();
     Runnable mErrorRunnable;
 
     // Convenience runnables
@@ -47,15 +49,18 @@
     public ReferenceCountedTrigger(Context context, Runnable firstIncRunnable,
                                    Runnable lastDecRunnable, Runnable errorRunanable) {
         mContext = context;
-        mFirstIncRunnable = firstIncRunnable;
-        mLastDecRunnable = lastDecRunnable;
+        if (firstIncRunnable != null) mFirstIncRunnables.add(firstIncRunnable);
+        if (lastDecRunnable != null) mLastDecRunnables.add(lastDecRunnable);
         mErrorRunnable = errorRunanable;
     }
 
     /** Increments the ref count */
     public void increment() {
-        if (mCount == 0 && mFirstIncRunnable != null) {
-            mFirstIncRunnable.run();
+        if (mCount == 0 && !mFirstIncRunnables.isEmpty()) {
+            int numRunnables = mFirstIncRunnables.size();
+            for (int i = 0; i < numRunnables; i++) {
+                mFirstIncRunnables.get(i).run();
+            }
         }
         mCount++;
     }
@@ -65,11 +70,19 @@
         return mIncrementRunnable;
     }
 
+    /** Adds a runnable to the last-decrement runnables list. */
+    public void addLastDecrementRunnable(Runnable r) {
+        mLastDecRunnables.add(r);
+    }
+
     /** Decrements the ref count */
     public void decrement() {
         mCount--;
-        if (mCount == 0 && mLastDecRunnable != null) {
-            mLastDecRunnable.run();
+        if (mCount == 0 && !mLastDecRunnables.isEmpty()) {
+            int numRunnables = mLastDecRunnables.size();
+            for (int i = 0; i < numRunnables; i++) {
+                mLastDecRunnables.get(i).run();
+            }
         } else if (mCount < 0) {
             if (mErrorRunnable != null) {
                 mErrorRunnable.run();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 55f9335..8f61e72 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -100,6 +100,16 @@
     Rect mTmpRect2 = new Rect();
     LayoutInflater mInflater;
 
+    Runnable mReturnAllViewsToPoolRunnable = new Runnable() {
+        @Override
+        public void run() {
+            int childCount = getChildCount();
+            for (int i = childCount - 1; i >= 0; i--) {
+                mViewPool.returnViewToPool((TaskView) getChildAt(i));
+            }
+        }
+    };
+
     public TaskStackView(Context context, TaskStack stack) {
         super(context);
         mConfig = RecentsConfiguration.getInstance();
@@ -904,6 +914,9 @@
             TaskView tv = (TaskView) getChildAt(i);
             tv.startExitToHomeAnimation(ctx);
         }
+
+        // Add a runnable to the post animation ref counter to clear all the views
+        ctx.postAnimationTrigger.addLastDecrementRunnable(mReturnAllViewsToPoolRunnable);
     }
 
     @Override
@@ -936,15 +949,14 @@
     public void onStackTaskRemoved(TaskStack stack, Task t) {
         // Remove the view associated with this task, we can't rely on updateTransforms
         // to work here because the task is no longer in the list
-        int childCount = getChildCount();
-        for (int i = childCount - 1; i >= 0; i--) {
-            TaskView tv = (TaskView) getChildAt(i);
-            if (tv.getTask() == t) {
-                mViewPool.returnViewToPool(tv);
-                break;
-            }
+        TaskView tv = getChildViewForTask(t);
+        if (tv != null) {
+            mViewPool.returnViewToPool(tv);
         }
 
+        // Notify the callback that we've removed the task and it can clean up after it
+        mCb.onTaskRemoved(t);
+
         // Update the min/max scroll and animate other task views into their new positions
         updateMinMaxScroll(true);
         int movement = (int) (Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height());
@@ -1193,7 +1205,6 @@
         // Request that this tasks's data be filled
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         loader.loadTaskData(task);
-
         // Find the index where this task should be placed in the children
         int insertIndex = -1;
         int childCount = getChildCount();
@@ -1275,8 +1286,6 @@
         Task task = tv.getTask();
         // Remove the task from the view
         mStack.removeTask(task);
-        // Notify the callback that we've removed the task and it can clean up after it
-        mCb.onTaskRemoved(task);
     }
 
     /**** View.OnClickListener Implementation ****/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 8d19f50..f6f78e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -119,6 +119,7 @@
 
     private NotificationBackgroundView mBackgroundNormal;
     private NotificationBackgroundView mBackgroundDimmed;
+    private NotificationScrimView mScrimView;
     private ObjectAnimator mBackgroundAnimator;
     private RectF mAppearAnimationRect = new RectF();
     private PorterDuffColorFilter mAppearAnimationFilter;
@@ -153,6 +154,7 @@
         mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
         updateBackground();
         updateBackgroundResources();
+        mScrimView = (NotificationScrimView) findViewById(R.id.scrim_view);
     }
 
     private final Runnable mTapTimeoutRunnable = new Runnable() {
@@ -379,6 +381,7 @@
         setPivotY(actualHeight / 2);
         mBackgroundNormal.setActualHeight(actualHeight);
         mBackgroundDimmed.setActualHeight(actualHeight);
+        mScrimView.setActualHeight(actualHeight);
     }
 
     @Override
@@ -386,6 +389,7 @@
         super.setClipTopAmount(clipTopAmount);
         mBackgroundNormal.setClipTopAmount(clipTopAmount);
         mBackgroundDimmed.setClipTopAmount(clipTopAmount);
+        mScrimView.setClipTopAmount(clipTopAmount);
     }
 
     @Override
@@ -405,6 +409,11 @@
         }
     }
 
+    @Override
+    public void setScrimAmount(float scrimAmount) {
+        mScrimView.setAlpha(scrimAmount);
+    }
+
     private void startAppearAnimation(boolean isAppearing,
             float translationDirection, long delay, final Runnable onFinishedRunnable) {
         if (mAppearAnimator != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 5bad602..5981898 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -212,13 +212,6 @@
         return mShowingPublic ? mRowMinHeight : mMaxExpandHeight;
     }
 
-    /**
-     * @return the potential height this view could expand in addition.
-     */
-    public int getExpandPotential() {
-        return getIntrinsicHeight() - getActualHeight();
-    }
-
     @Override
     public boolean isContentExpandable() {
         NotificationContentView showingLayout = getShowingLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index ac2537c..4d4a8ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -223,6 +223,8 @@
 
     public abstract void performAddAnimation(long delay);
 
+    public abstract void setScrimAmount(float scrimAmount);
+
     /**
      * A listener notifying when {@link #getActualHeight} changes.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 5cde979..f919501 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -17,12 +17,16 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.view.Gravity;
 import android.view.View;
-
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
 import android.widget.FrameLayout;
+
 import com.android.systemui.R;
 
 /**
@@ -32,6 +36,8 @@
  */
 public class NotificationContentView extends FrameLayout {
 
+    private static final long ANIMATION_DURATION_LENGTH = 170;
+
     private final Rect mClipBounds = new Rect();
 
     private View mContractedChild;
@@ -41,10 +47,17 @@
     private int mClipTopAmount;
     private int mActualHeight;
 
+    private final Interpolator mLinearInterpolator = new LinearInterpolator();
+
+    private boolean mContractedVisible = true;
+
+    private Paint mFadePaint = new Paint();
+
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         mActualHeight = mSmallHeight;
+        mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
     }
 
     @Override
@@ -60,7 +73,7 @@
         sanitizeContractedLayoutParams(child);
         addView(child);
         mContractedChild = child;
-        selectLayout();
+        selectLayout(false /* animate */, true /* force */);
     }
 
     public void setExpandedChild(View child) {
@@ -69,12 +82,12 @@
         }
         addView(child);
         mExpandedChild = child;
-        selectLayout();
+        selectLayout(false /* animate */, true /* force */);
     }
 
     public void setActualHeight(int actualHeight) {
         mActualHeight = actualHeight;
-        selectLayout();
+        selectLayout(true /* animate */, false /* force */);
         updateClipping();
     }
 
@@ -104,26 +117,60 @@
         contractedChild.setLayoutParams(lp);
     }
 
-    private void selectLayout() {
-        if (mActualHeight <= mSmallHeight || mExpandedChild == null) {
-            if (mContractedChild != null && mContractedChild.getVisibility() != View.VISIBLE) {
-                mContractedChild.setVisibility(View.VISIBLE);
-            }
-            if (mExpandedChild != null && mExpandedChild.getVisibility() != View.INVISIBLE) {
-                mExpandedChild.setVisibility(View.INVISIBLE);
-            }
-        } else {
-            if (mExpandedChild.getVisibility() != View.VISIBLE) {
-                mExpandedChild.setVisibility(View.VISIBLE);
-            }
-            if (mContractedChild != null && mContractedChild.getVisibility() != View.INVISIBLE) {
-                mContractedChild.setVisibility(View.INVISIBLE);
+    private void selectLayout(boolean animate, boolean force) {
+        if (mContractedChild == null) {
+            return;
+        }
+        boolean showContractedChild = showContractedChild();
+        if (showContractedChild != mContractedVisible || force) {
+            if (animate && mExpandedChild != null) {
+                runSwitchAnimation(showContractedChild);
+            } else if (mExpandedChild != null) {
+                mContractedChild.setVisibility(showContractedChild ? View.VISIBLE : View.INVISIBLE);
+                mContractedChild.setAlpha(showContractedChild ? 1f : 0f);
+                mExpandedChild.setVisibility(showContractedChild ? View.INVISIBLE : View.VISIBLE);
+                mExpandedChild.setAlpha(showContractedChild ? 0f : 1f);
             }
         }
+        mContractedVisible = showContractedChild;
+    }
+
+    private void runSwitchAnimation(final boolean showContractedChild) {
+        mContractedChild.setVisibility(View.VISIBLE);
+        mExpandedChild.setVisibility(View.VISIBLE);
+        mContractedChild.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint);
+        mExpandedChild.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint);
+        setLayerType(LAYER_TYPE_HARDWARE, null);
+        mContractedChild.animate()
+                .alpha(showContractedChild ? 1f : 0f)
+                .setDuration(ANIMATION_DURATION_LENGTH)
+                .setInterpolator(mLinearInterpolator);
+        mExpandedChild.animate()
+                .alpha(showContractedChild ? 0f : 1f)
+                .setDuration(ANIMATION_DURATION_LENGTH)
+                .setInterpolator(mLinearInterpolator)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        mContractedChild.setLayerType(LAYER_TYPE_NONE, null);
+                        mExpandedChild.setLayerType(LAYER_TYPE_NONE, null);
+                        setLayerType(LAYER_TYPE_NONE, null);
+                        mContractedChild.setVisibility(showContractedChild
+                                ? View.VISIBLE
+                                : View.INVISIBLE);
+                        mExpandedChild.setVisibility(showContractedChild
+                                ? View.INVISIBLE
+                                : View.VISIBLE);
+                    }
+                });
+    }
+
+    private boolean showContractedChild() {
+        return mActualHeight <= mSmallHeight || mExpandedChild == null;
     }
 
     public void notifyContentUpdated() {
-        selectLayout();
+        selectLayout(false /* animate */, true /* force */);
     }
 
     public boolean isContentExpandable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationScrimView.java
new file mode 100644
index 0000000..440b2c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationScrimView.java
@@ -0,0 +1,79 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.keyguard.R;
+
+/**
+ * A view that can be used for both the dimmed and normal background of an notification.
+ */
+public class NotificationScrimView extends View {
+
+    private Drawable mBackground;
+    private int mClipTopAmount;
+    private int mActualHeight;
+
+    public NotificationScrimView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mBackground = getResources().getDrawable(R.drawable.notification_scrim);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        draw(canvas, mBackground);
+    }
+
+    private void draw(Canvas canvas, Drawable drawable) {
+        if (drawable != null) {
+            drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
+            drawable.draw(canvas);
+        }
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || who == mBackground;
+    }
+
+    public void setActualHeight(int actualHeight) {
+        mActualHeight = actualHeight;
+        invalidate();
+    }
+
+    public int getActualHeight() {
+        return mActualHeight;
+    }
+
+    public void setClipTopAmount(int clipTopAmount) {
+        mClipTopAmount = clipTopAmount;
+        invalidate();
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+
+        // Prevents this view from creating a layer when alpha is animating.
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
index f80f0fd..650abaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -121,4 +121,9 @@
     public void performAddAnimation(long delay) {
         performVisibilityAnimation(true);
     }
+
+    @Override
+    public void setScrimAmount(float scrimAmount) {
+        // We don't need to scrim the speedbumps
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 97aa993..63698e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -58,6 +58,7 @@
     private ImageView mCameraImageView;
     private ImageView mPhoneImageView;
     private ImageView mLockIcon;
+    private View mIndicationText;
 
     private ActivityStarter mActivityStarter;
     private UnlockMethodCache mUnlockMethodCache;
@@ -87,6 +88,7 @@
         mCameraImageView = (ImageView) findViewById(R.id.camera_button);
         mPhoneImageView = (ImageView) findViewById(R.id.phone_button);
         mLockIcon = (ImageView) findViewById(R.id.lock_icon);
+        mIndicationText = findViewById(R.id.keyguard_indication_text);
         watchForCameraPolicyChanges();
         watchForAccessibilityChanges();
         updateCameraVisibility();
@@ -231,6 +233,10 @@
         return mLockIcon;
     }
 
+    public View getIndicationView() {
+        return mIndicationText;
+    }
+
     @Override
     public void onMethodSecureChanged(boolean methodSecure) {
         updateTrust();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 6a83a5e..319096d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -18,6 +18,7 @@
 
 import android.content.res.Resources;
 import android.graphics.Path;
+import android.view.animation.AccelerateInterpolator;
 import android.view.animation.PathInterpolator;
 
 import com.android.systemui.R;
@@ -31,6 +32,10 @@
 
     private static final float CLOCK_RUBBERBAND_FACTOR_MIN = 0.08f;
     private static final float CLOCK_RUBBERBAND_FACTOR_MAX = 0.8f;
+    private static final float CLOCK_SCALE_FADE_START = 0.95f;
+    private static final float CLOCK_SCALE_FADE_END = 0.75f;
+    private static final float CLOCK_SCALE_FADE_END_NO_NOTIFS = 0.5f;
+
 
     private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f;
     private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f;
@@ -61,6 +66,8 @@
         sSlowDownInterpolator = new PathInterpolator(path);
     }
 
+    private AccelerateInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
+
     /**
      * Refreshes the dimension values.
      */
@@ -87,18 +94,29 @@
     }
 
     public void run(Result result) {
-        int y = getClockY() - mKeyguardStatusHeight/2;
+        int y = getClockY() - mKeyguardStatusHeight / 2;
         float clockAdjustment = getClockYExpansionAdjustment();
         float topPaddingAdjMultiplier = getTopPaddingAdjMultiplier();
         result.stackScrollerPaddingAdjustment = (int) (clockAdjustment*topPaddingAdjMultiplier);
         int clockNotificationsPadding = getClockNotificationsPadding()
                 + result.stackScrollerPaddingAdjustment;
         int padding = y + clockNotificationsPadding;
-        y += clockAdjustment;
         result.clockY = y;
         result.stackScrollerPadding = mKeyguardStatusHeight + padding;
-        result.clockAlpha = getClockAlpha(result.stackScrollerPadding
-                - (y + mKeyguardStatusHeight));
+        result.clockScale = getClockScale(result.stackScrollerPadding,
+                result.clockY,
+                y + getClockNotificationsPadding() + mKeyguardStatusHeight);
+        result.clockAlpha = getClockAlpha(result.clockScale);
+    }
+
+    private float getClockScale(int notificationPadding, int clockY, int startPadding) {
+        float scaleMultiplier = getNotificationAmountT() == 0 ? 6.0f : 5.0f;
+        float scaleEnd = clockY - mKeyguardStatusHeight * scaleMultiplier;
+        float distanceToScaleEnd = notificationPadding - scaleEnd;
+        float progress = distanceToScaleEnd / (startPadding - scaleEnd);
+        progress = Math.max(0.0f, Math.min(progress, 1.0f));
+        progress = mAccelerateInterpolator.getInterpolation(progress);
+        return progress;
     }
 
     private int getClockNotificationsPadding() {
@@ -144,11 +162,12 @@
                 + t * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX;
     }
 
-    private float getClockAlpha(int clockNotificationPadding) {
-        float t = getNotificationAmountT();
-        t = (float) Math.pow(t, 0.3f);
-        float multiplier = 1 + 2 * (1 - t);
-        float alpha = 1 + (float) clockNotificationPadding * multiplier / mKeyguardStatusHeight * 3;
+    private float getClockAlpha(float scale) {
+        float fadeEnd = getNotificationAmountT() == 0.0f
+                ? CLOCK_SCALE_FADE_END_NO_NOTIFS
+                : CLOCK_SCALE_FADE_END;
+        float alpha = (scale - fadeEnd)
+                / (CLOCK_SCALE_FADE_START - fadeEnd);
         return Math.max(0, Math.min(1, alpha));
     }
 
@@ -168,6 +187,11 @@
         public int clockY;
 
         /**
+         * The scale of the Clock
+         */
+        public float clockScale;
+
+        /**
          * The alpha value of the clock.
          */
         public float clockAlpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index dde95bf..a6ce5d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -32,6 +32,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableView;
@@ -48,6 +49,11 @@
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
         KeyguardPageSwipeHelper.Callback {
 
+    // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
+    // changed.
+    private static final int CAP_HEIGHT = 1456;
+    private static final int FONT_HEIGHT = 2163;
+
     private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
 
     private KeyguardPageSwipeHelper mPageSwiper;
@@ -56,7 +62,7 @@
     private View mQsPanel;
     private View mKeyguardStatusView;
     private ObservableScrollView mScrollView;
-    private View mStackScrollerContainer;
+    private TextView mClockView;
 
     private NotificationStackScrollLayout mNotificationStackScroller;
     private int mNotificationTopPadding;
@@ -105,9 +111,11 @@
             new KeyguardClockPositionAlgorithm.Result();
     private boolean mIsSwipedHorizontally;
     private boolean mIsExpanding;
-    private KeyguardBottomAreaView mKeyguardBottomArea;
+
     private boolean mBlockTouches;
     private ArrayList<View> mSwipeTranslationViews = new ArrayList<>();
+    private int mNotificationScrimWaitDistance;
+    private boolean mOnNotificationsOnDown;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -135,9 +143,9 @@
         mHeader.getBackgroundView().setOnClickListener(this);
         mHeader.setOverlayParent(this);
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
-        mStackScrollerContainer = findViewById(R.id.notification_container_parent);
         mQsContainer = findViewById(R.id.quick_settings_container);
         mQsPanel = findViewById(R.id.quick_settings_panel);
+        mClockView = (TextView) findViewById(R.id.clock_view);
         mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
         mScrollView.setListener(this);
         mNotificationStackScroller = (NotificationStackScrollLayout)
@@ -169,12 +177,19 @@
                 getResources().getDimensionPixelSize(R.dimen.header_notifications_collide_distance);
         mUnlockMoveDistance = getResources().getDimensionPixelOffset(R.dimen.unlock_move_distance);
         mClockPositionAlgorithm.loadDimens(getResources());
+        mNotificationScrimWaitDistance =
+                getResources().getDimensionPixelSize(R.dimen.notification_scrim_wait_distance);
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
+        // Update Clock Pivot
+        mKeyguardStatusView.setPivotX(getWidth() / 2);
+        mKeyguardStatusView.setPivotY(
+                (FONT_HEIGHT - CAP_HEIGHT) / 2048f * mClockView.getTextSize());
+
         // Calculate quick setting heights.
         mQsMinExpansionHeight = mHeader.getCollapsedHeight() + mQsPeekHeight;
         mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
@@ -197,7 +212,7 @@
      * showing.
      */
     private void positionClockAndNotifications() {
-        boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending();
+        boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
         int stackScrollerPadding;
         if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
             int bottom = mStackScrollerOverscrolling
@@ -215,17 +230,17 @@
                     getHeight(),
                     mKeyguardStatusView.getHeight());
             mClockPositionAlgorithm.run(mClockPositionResult);
-            if (animateClock || mClockAnimator != null) {
+            if (animate || mClockAnimator != null) {
                 startClockAnimation(mClockPositionResult.clockY);
             } else {
                 mKeyguardStatusView.setY(mClockPositionResult.clockY);
             }
-            applyClockAlpha(mClockPositionResult.clockAlpha);
+            updateClock(mClockPositionResult.clockAlpha, mClockPositionResult.clockScale);
             stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
             mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment;
         }
         mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
-        requestScrollerTopPaddingUpdate(animateClock);
+        requestScrollerTopPaddingUpdate(animate);
     }
 
     private void startClockAnimation(int y) {
@@ -258,13 +273,10 @@
         });
     }
 
-    private void applyClockAlpha(float alpha) {
-        if (alpha != 1.0f) {
-            mKeyguardStatusView.setLayerType(LAYER_TYPE_HARDWARE, null);
-        } else {
-            mKeyguardStatusView.setLayerType(LAYER_TYPE_NONE, null);
-        }
+    private void updateClock(float alpha, float scale) {
         mKeyguardStatusView.setAlpha(alpha);
+        mKeyguardStatusView.setScaleX(scale);
+        mKeyguardStatusView.setScaleY(scale);
     }
 
     public void animateToFullShade() {
@@ -344,6 +356,7 @@
                 mInitialTouchX = x;
                 initVelocityTracker();
                 trackMovement(event);
+                mOnNotificationsOnDown = isOnNotifications(x, y);
                 if (shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) {
                     getParent().requestDisallowInterceptTouchEvent(true);
                 }
@@ -391,6 +404,8 @@
                 if (mQsTracking) {
                     flingQsWithCurrentVelocity();
                     mQsTracking = false;
+                } else if (mQsFullyExpanded && mOnNotificationsOnDown) {
+                    flingSettings(0 /* vel */, false /* expand */);
                 }
                 mIntercepting = false;
                 break;
@@ -398,6 +413,10 @@
         return !mQsExpanded && super.onInterceptTouchEvent(event);
     }
 
+    private boolean isOnNotifications(float x, float y) {
+        return mNotificationStackScroller.getChildAtPosition(x, y) != null;
+    }
+
     @Override
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
 
@@ -577,9 +596,17 @@
         mHeader.setExpansion(height - mQsPeekHeight);
         setQsTranslation(height);
         requestScrollerTopPaddingUpdate(false /* animate */);
+        updateNotificationScrim(height);
         mStatusBar.userActivity();
     }
 
+    private void updateNotificationScrim(float height) {
+        int startDistance = mQsMinExpansionHeight + mNotificationScrimWaitDistance;
+        float progress = (height - startDistance) / (mQsMaxExpansionHeight - startDistance);
+        progress = Math.max(0.0f, Math.min(progress, 1.0f));
+        mNotificationStackScroller.setScrimAlpha(progress);
+    }
+
     private void setQsTranslation(float height) {
         mQsContainer.setY(height - mQsContainer.getHeight());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 1f3098d..12aa004 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -62,6 +62,7 @@
     protected int mTouchSlop;
     protected boolean mHintAnimationRunning;
     private boolean mOverExpandedBeforeFling;
+    private float mOriginalIndicationY;
 
     private ValueAnimator mHeightAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -82,6 +83,7 @@
 
     private Interpolator mLinearOutSlowInInterpolator;
     private Interpolator mBounceInterpolator;
+    protected KeyguardBottomAreaView mKeyguardBottomArea;
 
     protected void onExpandingFinished() {
         mBar.onExpandingFinished();
@@ -652,6 +654,22 @@
         });
         animator.start();
         mHeightAnimator = animator;
+        mOriginalIndicationY = mKeyguardBottomArea.getIndicationView().getY();
+        mKeyguardBottomArea.getIndicationView().animate()
+                .y(mOriginalIndicationY - mHintDistance)
+                .setDuration(250)
+                .setInterpolator(mLinearOutSlowInInterpolator)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        mKeyguardBottomArea.getIndicationView().animate()
+                                .y(mOriginalIndicationY)
+                                .setDuration(450)
+                                .setInterpolator(mBounceInterpolator)
+                                .start();
+                    }
+                })
+                .start();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1da7dab..7016c0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -35,6 +35,7 @@
 import android.animation.ValueAnimator;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
@@ -64,6 +65,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.provider.Settings.SettingNotFoundException;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
@@ -82,7 +84,6 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewPropertyAnimator;
 import android.view.ViewStub;
-import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Animation;
@@ -123,6 +124,7 @@
 import com.android.systemui.statusbar.policy.CastControllerImpl;
 import com.android.systemui.statusbar.policy.DateView;
 import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
+import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.LocationControllerImpl;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
@@ -211,6 +213,7 @@
     ZenModeController mZenModeController;
     CastControllerImpl mCastController;
     VolumeComponent mVolumeComponent;
+    KeyguardUserSwitcher mKeyguardUserSwitcher;
 
     int mNaturalBarHeight = -1;
     int mIconSize = -1;
@@ -260,6 +263,10 @@
     boolean mLeaveOpenOnKeyguardHide;
     KeyguardIndicationController mKeyguardIndicationController;
 
+    private boolean mKeyguardFadingAway;
+    private long mKeyguardFadingAwayDelay;
+    private long mKeyguardFadingAwayDuration;
+
     int mKeyguardMaxNotificationCount;
     View mDateTimeView;
 
@@ -399,7 +406,9 @@
     private boolean mSettingsCancelled;
     private boolean mSettingsClosing;
     private boolean mVisible;
+    private boolean mWaitingForKeyguardExit;
 
+    private Interpolator mLinearOutSlowIn;
     private Interpolator mAlphaOut = new PathInterpolator(0f, 0.4f, 1f, 1f);
     private Interpolator mAlphaIn = new PathInterpolator(0f, 0f, 0.8f, 1f);
 
@@ -713,6 +722,8 @@
         final SignalClusterView signalCluster =
                 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
 
+        mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
+                (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mHeader);
 
         mNetworkController.addSignalCluster(signalCluster);
         signalCluster.setNetworkController(mNetworkController);
@@ -893,6 +904,14 @@
         }
     };
 
+    private View.OnLongClickListener mLockToAppClickListener = new View.OnLongClickListener() {
+        @Override
+        public boolean onLongClick(View v) {
+            toggleLockedApp();
+            return true;
+        }
+    };
+
     private int mShowSearchHoldoff = 0;
     private Runnable mShowSearchPanel = new Runnable() {
         public void run() {
@@ -936,6 +955,8 @@
 
         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
         mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
+        mNavigationBarView.getRecentsButton().setLongClickable(true);
+        mNavigationBarView.getRecentsButton().setOnLongClickListener(mLockToAppClickListener);
         mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
         updateSearchPanel();
     }
@@ -1453,7 +1474,7 @@
     }
 
     private int adjustDisableFlags(int state) {
-        if (mExpandedVisible) {
+        if (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit) {
             state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
             state |= StatusBarManager.DISABLE_SYSTEM_INFO;
         }
@@ -1501,19 +1522,9 @@
         if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
             mSystemIconArea.animate().cancel();
             if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-                mSystemIconArea.animate()
-                    .alpha(0f)
-                    .withLayer()
-                    .setDuration(160)
-                    .setInterpolator(mAlphaIn)
-                    .setListener(mMakeIconsInvisible);
+                animateStatusBarHide(mSystemIconArea);
             } else {
-                mSystemIconArea.setVisibility(View.VISIBLE);
-                mSystemIconArea.animate()
-                    .alpha(1f)
-                    .withLayer()
-                    .setInterpolator(mAlphaOut)
-                    .setDuration(320);
+                animateStatusBarShow(mSystemIconArea);
             }
         }
 
@@ -1546,25 +1557,48 @@
                 if (mTicking) {
                     haltTicker();
                 }
-
-                mNotificationIcons.animate()
-                    .alpha(0f)
-                    .withLayer()
-                    .setDuration(160)
-                    .setInterpolator(mAlphaIn)
-                    .setListener(mMakeIconsInvisible)
-                    .start();
+                animateStatusBarHide(mNotificationIcons);
             } else {
-                mNotificationIcons.setVisibility(View.VISIBLE);
-                mNotificationIcons.animate()
-                    .alpha(1f)
-                    .withLayer()
-                    .setInterpolator(mAlphaOut)
-                    .setDuration(320);
+                animateStatusBarShow(mNotificationIcons);
             }
         }
     }
 
+    /**
+     * Animates {@code v}, a view that is part of the status bar, out.
+     */
+    private void animateStatusBarHide(View v) {
+        v.animate()
+                .alpha(0f)
+                .withLayer()
+                .setDuration(160)
+                .setInterpolator(mAlphaIn)
+                .setStartDelay(0)
+                .setListener(mMakeIconsInvisible)
+                .start();
+    }
+
+    /**
+     * Animates {@code v}, a view that is part of the status bar, in.
+     */
+    private void animateStatusBarShow(View v) {
+        v.setVisibility(View.VISIBLE);
+        v.animate()
+                .alpha(1f)
+                .withLayer()
+                .setInterpolator(mAlphaOut)
+                .setDuration(320)
+                .setStartDelay(0);
+
+        // Synchronize the motion with the Keyguard fading if necessary.
+        if (mKeyguardFadingAway) {
+            v.animate()
+                    .setDuration(mKeyguardFadingAwayDuration)
+                    .setInterpolator(mLinearOutSlowIn)
+                    .setStartDelay(mKeyguardFadingAwayDelay);
+        }
+    }
+
     @Override
     protected BaseStatusBar.H createHandler() {
         return new PhoneStatusBar.H();
@@ -1666,6 +1700,7 @@
         mStatusBarWindowManager.setStatusBarExpanded(true);
 
         visibilityChanged(true);
+        mWaitingForKeyguardExit = false;
         disable(mDisabledUnmodified);
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
     }
@@ -1859,8 +1894,8 @@
         }
 
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
-        disable(mDisabledUnmodified);
         showBouncer();
+        disable(mDisabledUnmodified);
     }
 
     public boolean interceptTouchEvent(MotionEvent event) {
@@ -2574,6 +2609,8 @@
         if (mQSPanel != null) mQSPanel.updateResources();
 
         loadDimens();
+        mLinearOutSlowIn = AnimationUtils.loadInterpolator(
+                mContext, android.R.interpolator.linear_out_slow_in);
     }
 
     protected void loadDimens() {
@@ -2901,6 +2938,27 @@
         updateKeyguardState();
     }
 
+    /**
+     * Notifies the status bar the Keyguard is fading away with the specified timings.
+     *
+     * @param delay the animation delay in miliseconds
+     * @param fadeoutDuration the duration of the exit animation, in milliseconds
+     */
+    public void setKeyguardFadingAway(long delay, long fadeoutDuration) {
+        mKeyguardFadingAway = true;
+        mKeyguardFadingAwayDelay = delay;
+        mKeyguardFadingAwayDuration = fadeoutDuration;
+        mWaitingForKeyguardExit = false;
+        disable(mDisabledUnmodified);
+    }
+
+    /**
+     * Notifies that the Keyguard fading away animation is done.
+     */
+    public void finishKeyguardFadingAway() {
+        mKeyguardFadingAway = false;
+    }
+
     private void updatePublicMode() {
         setLockscreenPublicMode(
                 (mStatusBarKeyguardViewManager.isShowing() || 
@@ -2913,9 +2971,11 @@
             mKeyguardStatusView.setVisibility(View.VISIBLE);
             mKeyguardIndicationController.setVisible(true);
             mNotificationPanel.resetViews();
+            mKeyguardUserSwitcher.setKeyguard(true);
         } else {
             mKeyguardStatusView.setVisibility(View.GONE);
             mKeyguardIndicationController.setVisible(false);
+            mKeyguardUserSwitcher.setKeyguard(false);
         }
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             mKeyguardBottomArea.setVisibility(View.VISIBLE);
@@ -2975,6 +3035,7 @@
 
     private void showBouncer() {
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+            mWaitingForKeyguardExit = true;
             mStatusBarKeyguardViewManager.dismiss();
         }
     }
@@ -3125,6 +3186,12 @@
         mSystemIconArea.addView(mSystemIcons, 0);
     }
 
+    @Override
+    public void setBouncerShowing(boolean bouncerShowing) {
+        super.setBouncerShowing(bouncerShowing);
+        disable(mDisabledUnmodified);
+    }
+
     public void onScreenTurnedOff() {
         mStackScroller.setAnimationsEnabled(false);
     }
@@ -3133,6 +3200,28 @@
         mStackScroller.setAnimationsEnabled(true);
     }
 
+    public void toggleLockedApp() {
+        Log.d(TAG, "Trying to toggle lock-to-app");
+        try {
+            IActivityManager activityManager = ActivityManagerNative.getDefault();
+            if (activityManager.isInLockTaskMode()) {
+                activityManager.stopLockTaskModeOnCurrent();
+            } else {
+                try {
+                    boolean lockToAppEnabled = Settings.System.getInt(mContext.getContentResolver(),
+                            Settings.System.LOCK_TO_APP_ENABLED) != 0;
+                    if (lockToAppEnabled) {
+                        activityManager.startLockTaskModeOnCurrent();
+                    }
+                } catch (SettingNotFoundException e) {
+                    // No setting, not enabled.
+                }
+            }
+        } catch (RemoteException e) {
+            Log.d(TAG, "Unable to toggle Lock-to-app", e);
+        }
+    }
+
     private final Runnable mUserActivity = new Runnable() {
         @Override
         public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 1712124..fc10a08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -63,6 +63,7 @@
 
     private boolean mShowEmergencyCallsOnly;
     private boolean mShowChargingInfo;
+    private boolean mKeyguardUserSwitcherShowing;
 
     private int mCollapsedHeight;
     private int mExpandedHeight;
@@ -72,6 +73,7 @@
     private int mNormalWidth;
     private int mPadding;
     private int mMultiUserExpandedMargin;
+    private int mSystemIconsSwitcherHiddenExpandedMargin;
 
     private ActivityStarter mActivityStarter;
     private BrightnessController mBrightnessController;
@@ -125,7 +127,8 @@
         mPadding = getResources().getDimensionPixelSize(R.dimen.notification_side_padding);
         mMultiUserExpandedMargin =
                 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin);
-
+        mSystemIconsSwitcherHiddenExpandedMargin = getResources().getDimensionPixelSize(
+                R.dimen.system_icons_switcher_hidden_expanded_margin);
     }
 
     public void setActivityStarter(ActivityStarter activityStarter) {
@@ -216,12 +219,15 @@
                 ? VISIBLE : GONE);
         mChargingInfo.setVisibility(mExpanded && !mOverscrolled && mShowChargingInfo
                 && !mShowEmergencyCallsOnly ? VISIBLE : GONE);
+        mMultiUserSwitch.setVisibility(mExpanded || !mKeyguardUserSwitcherShowing
+                ? VISIBLE : GONE);
     }
 
     private void updateSystemIconsLayoutParams() {
         RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsContainer.getLayoutParams();
         boolean systemIconsAboveClock = mExpanded && !mOverscrolled
                 && mShowChargingInfo && !mShowEmergencyCallsOnly;
+        lp.setMarginEnd(0);
         if (systemIconsAboveClock) {
             lp.addRule(ALIGN_PARENT_START);
             lp.removeRule(START_OF);
@@ -230,7 +236,11 @@
                     ? mSettingsButton.getId()
                     : mMultiUserSwitch.getId());
             lp.removeRule(ALIGN_PARENT_START);
+            if (mMultiUserSwitch.getVisibility() == GONE) {
+                lp.setMarginEnd(mSystemIconsSwitcherHiddenExpandedMargin);
+            }
         }
+        mSystemIconsContainer.setLayoutParams(lp);
 
         RelativeLayout.LayoutParams clockLp = (LayoutParams) mDateTime.getLayoutParams();
         if (systemIconsAboveClock) {
@@ -238,6 +248,7 @@
         } else {
             clockLp.addRule(BELOW, mEmergencyCallsOnly.getId());
         }
+        mDateTime.setLayoutParams(clockLp);
     }
 
     private void updateBrightnessControllerState() {
@@ -385,4 +396,11 @@
     public void setChargingInfo(CharSequence chargingInfo) {
         mChargingInfo.setText(chargingInfo);
     }
+
+    public void setKeyguardUserSwitcherShowing(boolean showing) {
+        // STOPSHIP: NOT CALLED PROPERLY WHEN GOING TO FULL SHADE AND RETURNING!?!
+        mKeyguardUserSwitcherShowing = showing;
+        updateVisibilities();
+        updateSystemIconsLayoutParams();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 09e4d94..a36f3d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -190,19 +190,23 @@
      */
     public void hide(long startTime, long fadeoutDuration) {
         mShowing = false;
-        mPhoneStatusBar.hideKeyguard();
-        mStatusBarWindowManager.setKeyguardFadingAway(true);
-        mStatusBarWindowManager.setKeyguardShowing(false);
+
         long uptimeMillis = SystemClock.uptimeMillis();
         long delay = startTime - uptimeMillis;
         if (delay < 0) {
             delay = 0;
         }
+
+        mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration);
+        mPhoneStatusBar.hideKeyguard();
+        mStatusBarWindowManager.setKeyguardFadingAway(true);
+        mStatusBarWindowManager.setKeyguardShowing(false);
         mBouncer.animateHide(delay, fadeoutDuration);
         mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() {
             @Override
             public void run() {
                 mStatusBarWindowManager.setKeyguardFadingAway(false);
+                mPhoneStatusBar.finishKeyguardFadingAway();
             }
         });
         mViewMediatorCallback.keyguardGone();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
new file mode 100644
index 0000000..6f2642a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -0,0 +1,219 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import com.android.systemui.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * A view that displays a user image cropped to a circle with a frame.
+ */
+public class UserAvatarView extends View {
+
+    private int mActiveFrameColor;
+    private int mFrameColor;
+    private float mFrameWidth;
+    private Bitmap mBitmap;
+    private Drawable mDrawable;
+
+    private final Paint mFramePaint = new Paint();
+    private final Paint mBitmapPaint = new Paint();
+    private final Matrix mDrawMatrix = new Matrix();
+
+    private float mScale = 1;
+
+    public UserAvatarView(Context context, AttributeSet attrs,
+            int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        final TypedArray a = context.obtainStyledAttributes(
+                attrs, R.styleable.UserAvatarView, defStyleAttr, defStyleRes);
+        final int N = a.getIndexCount();
+        for (int i = 0; i < N; i++) {
+            int attr = a.getIndex(i);
+            switch (attr) {
+                case R.styleable.UserAvatarView_frameWidth:
+                    setFrameWidth(a.getDimension(attr, 0));
+                    break;
+                case R.styleable.UserAvatarView_activeFrameColor:
+                    setActiveFrameColor(a.getColor(attr, 0));
+                    break;
+                case R.styleable.UserAvatarView_frameColor:
+                    setFrameColor(a.getColor(attr, 0));
+                    break;
+            }
+        }
+        a.recycle();
+
+        mFramePaint.setAntiAlias(true);
+        mFramePaint.setStyle(Paint.Style.STROKE);
+        mBitmapPaint.setAntiAlias(true);
+    }
+
+    public UserAvatarView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public UserAvatarView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public UserAvatarView(Context context) {
+        this(context, null);
+    }
+
+    public void setBitmap(Bitmap bitmap) {
+        setDrawable(null);
+        mBitmap = bitmap;
+        if (mBitmap != null) {
+            mBitmapPaint.setShader(new BitmapShader(
+                    bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
+        } else {
+            mBitmapPaint.setShader(null);
+        }
+        configureBounds();
+        invalidate();
+    }
+
+    public void setFrameColor(int frameColor) {
+        mFrameColor = frameColor;
+        invalidate();
+    }
+
+    public void setActiveFrameColor(int activeFrameColor) {
+        mActiveFrameColor = activeFrameColor;
+        invalidate();
+    }
+
+    public void setFrameWidth(float frameWidth) {
+        mFrameWidth = frameWidth;
+        invalidate();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        configureBounds();
+    }
+
+    public void configureBounds() {
+        int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
+        int vheight = getHeight() - mPaddingTop - mPaddingBottom;
+
+        int dwidth;
+        int dheight;
+        if (mBitmap != null) {
+            dwidth = mBitmap.getWidth();
+            dheight = mBitmap.getHeight();
+        } else if (mDrawable != null) {
+            dwidth = mDrawable.getIntrinsicWidth();
+            dheight = mDrawable.getIntrinsicHeight();
+            mDrawable.setBounds(0, 0, dwidth, dheight);
+            vwidth -= 2 * (mFrameWidth - 1);
+            vheight -= 2 * (mFrameWidth - 1);
+        } else {
+            return;
+        }
+
+        float scale;
+        float dx;
+        float dy;
+
+        scale = Math.min((float) vwidth / (float) dwidth,
+                (float) vheight / (float) dheight);
+
+        dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
+        dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);
+
+        mDrawMatrix.setScale(scale, scale);
+        mDrawMatrix.postTranslate(dx, dy);
+        mScale = scale;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        int frameColor = isActivated() ? mActiveFrameColor : mFrameColor;
+        float halfW = getWidth() / 2f;
+        float halfH = getHeight() / 2f;
+        float halfSW = Math.min(halfH, halfW);
+        if (mBitmap != null && mScale > 0) {
+            int saveCount = canvas.getSaveCount();
+            canvas.save();
+            canvas.translate(mPaddingLeft, mPaddingTop);
+            canvas.concat(mDrawMatrix);
+            float halfBW = mBitmap.getWidth() / 2f;
+            float halfBH = mBitmap.getHeight() / 2f;
+            float halfBSW = Math.min(halfBH, halfBW);
+            canvas.drawCircle(halfBW, halfBH, halfBSW - mFrameWidth / mScale + 1, mBitmapPaint);
+            canvas.restoreToCount(saveCount);
+        } else if (mDrawable != null && mScale > 0) {
+            int saveCount = canvas.getSaveCount();
+            canvas.save();
+            canvas.translate(mPaddingLeft, mPaddingTop);
+            canvas.translate(mFrameWidth - 1, mFrameWidth - 1);
+            canvas.concat(mDrawMatrix);
+            mDrawable.draw(canvas);
+            canvas.restoreToCount(saveCount);
+        }
+        if (frameColor != 0) {
+            mFramePaint.setColor(frameColor);
+            mFramePaint.setStrokeWidth(mFrameWidth);
+            canvas.drawCircle(halfW, halfH, halfSW - mFrameWidth / 2f, mFramePaint);
+        }
+    }
+
+    public void setDrawable(Drawable d) {
+        if (mDrawable != null) {
+            mDrawable.setCallback(null);
+            unscheduleDrawable(mDrawable);
+        }
+        mDrawable = d;
+        if (d != null) {
+            d.setCallback(this);
+            if (d.isStateful()) {
+                d.setState(getDrawableState());
+            }
+            d.setLayoutDirection(getLayoutDirection());
+            configureBounds();
+        }
+        if (d != null) {
+            mBitmap = null;
+        }
+        configureBounds();
+        invalidate();
+    }
+
+    @Override
+    public void invalidateDrawable(Drawable dr) {
+        if (dr == mDrawable) {
+            invalidate();
+        } else {
+            super.invalidateDrawable(dr);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 330b599..0134fe8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -63,6 +63,7 @@
                     // Just an old-fashioned ImageView
                     performLongClick();
                 }
+                setPressed(false);
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
new file mode 100644
index 0000000..c90750c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -0,0 +1,209 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarHeaderView;
+import com.android.systemui.statusbar.phone.UserAvatarView;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+import android.view.WindowManagerGlobal;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages the user switcher on the Keyguard.
+ */
+public class KeyguardUserSwitcher implements View.OnClickListener {
+
+    private static final String TAG = "KeyguardUserSwitcher";
+
+    private final Context mContext;
+    private final ViewGroup mUserSwitcher;
+    private final UserManager mUserManager;
+    private final StatusBarHeaderView mHeader;
+
+    public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
+            StatusBarHeaderView header) {
+        mContext = context;
+        if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher)) {
+            mUserSwitcher = (ViewGroup) userSwitcher.inflate();
+            mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+            mHeader = header;
+            refresh();
+        } else {
+            mUserSwitcher = null;
+            mUserManager = null;
+            mHeader = null;
+        }
+    }
+
+    public void setKeyguard(boolean keyguard) {
+        if (mUserSwitcher != null) {
+            // TODO: Cache showUserSwitcherOnKeyguard().
+            if (keyguard && showUserSwitcherOnKeyguard()) {
+                show();
+                refresh();
+            } else {
+                hide();
+            }
+        }
+    }
+
+    /**
+     * @return true if the user switcher should be shown on the lock screen.
+     * @see android.os.UserManager#isUserSwitcherEnabled()
+     */
+    private boolean showUserSwitcherOnKeyguard() {
+        // TODO: Set isEdu. The edu provisioning process can add settings to Settings.Global.
+        boolean isEdu = false;
+        if (isEdu) {
+            return true;
+        }
+        List<UserInfo> users = mUserManager.getUsers(true /* excludeDying */);
+        int N = users.size();
+        int switchableUsers = 0;
+        for (int i = 0; i < N; i++) {
+            if (users.get(i).supportsSwitchTo()) {
+                switchableUsers++;
+            }
+        }
+        return switchableUsers > 1;
+    }
+
+    public void show() {
+        if (mUserSwitcher != null) {
+            // TODO: animate
+            mUserSwitcher.setVisibility(View.VISIBLE);
+            mHeader.setKeyguardUserSwitcherShowing(true);
+        }
+    }
+
+    private void hide() {
+        if (mUserSwitcher != null) {
+            // TODO: animate
+            mUserSwitcher.setVisibility(View.GONE);
+            mHeader.setKeyguardUserSwitcherShowing(false);
+        }
+    }
+
+    private void refresh() {
+        if (mUserSwitcher != null) {
+            new AsyncTask<Void, Void, ArrayList<UserData>>() {
+                @Override
+                protected ArrayList<UserData> doInBackground(Void... params) {
+                    return loadUsers();
+                }
+
+                @Override
+                protected void onPostExecute(ArrayList<UserData> userInfos) {
+                    bind(userInfos);
+                }
+            }.execute((Void[]) null);
+        }
+    }
+
+    private void bind(ArrayList<UserData> userList) {
+        mUserSwitcher.removeAllViews();
+        int N = userList.size();
+        for (int i = 0; i < N; i++) {
+            mUserSwitcher.addView(inflateUser(userList.get(i)));
+        }
+        // TODO: add Guest
+        // TODO: add (+) button
+    }
+
+    private View inflateUser(UserData user) {
+        View v = LayoutInflater.from(mUserSwitcher.getContext()).inflate(
+                R.layout.keyguard_user_switcher_item, mUserSwitcher, false);
+        TextView name = (TextView) v.findViewById(R.id.name);
+        UserAvatarView picture = (UserAvatarView) v.findViewById(R.id.picture);
+        name.setText(user.userInfo.name);
+        picture.setActivated(user.isCurrent);
+        if (user.userInfo.isGuest()) {
+            picture.setDrawable(mContext.getResources().getDrawable(R.drawable.ic_account_circle));
+        } else {
+            picture.setBitmap(user.userIcon);
+        }
+        v.setOnClickListener(this);
+        v.setTag(user.userInfo);
+        // TODO: mark which user is current for accessibility.
+        return v;
+    }
+
+    @Override
+    public void onClick(View v) {
+        switchUser(((UserInfo)v.getTag()).id);
+    }
+
+    // TODO: Factor out logic below and share with QS implementation.
+
+    private ArrayList<UserData> loadUsers() {
+        ArrayList<UserInfo> users = (ArrayList<UserInfo>) mUserManager
+                .getUsers(true /* excludeDying */);
+        int N = users.size();
+        ArrayList<UserData> result = new ArrayList<>(N);
+        int currentUser = -1;
+        try {
+            currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Couln't get current user.", e);
+        }
+        for (int i = 0; i < N; i++) {
+            UserInfo user = users.get(i);
+            if (user.supportsSwitchTo()) {
+                boolean isCurrent = user.id == currentUser;
+                result.add(new UserData(user, mUserManager.getUserIcon(user.id), isCurrent));
+            }
+        }
+        return result;
+    }
+
+    private void switchUser(int userId) {
+        try {
+            WindowManagerGlobal.getWindowManagerService().lockNow(null);
+            ActivityManagerNative.getDefault().switchUser(userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Couldn't switch user.", e);
+        }
+    }
+
+    private static class UserData {
+        final UserInfo userInfo;
+        final Bitmap userIcon;
+        final boolean isCurrent;
+
+        UserData(UserInfo userInfo, Bitmap userIcon, boolean isCurrent) {
+            this.userInfo = userInfo;
+            this.userIcon = userIcon;
+            this.isCurrent = isCurrent;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 6d92b05..fcc951e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -32,6 +32,7 @@
     private float mOverScrollTopAmount;
     private float mOverScrollBottomAmount;
     private int mSpeedBumpIndex = -1;
+    private float mScrimAmount;
 
     public int getScrollY() {
         return mScrollY;
@@ -85,6 +86,14 @@
         }
     }
 
+    public void setScrimAmount(float scrimAmount) {
+        mScrimAmount = scrimAmount;
+    }
+
+    public float getScrimAmount() {
+        return mScrimAmount;
+    }
+
     public float getOverScrollAmount(boolean top) {
         return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index ccbaed3..f6e9aef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -541,8 +541,9 @@
             if (slidingChild.getVisibility() == GONE) {
                 continue;
             }
-            float top = slidingChild.getTranslationY();
-            float bottom = top + slidingChild.getActualHeight();
+            float childTop = slidingChild.getTranslationY();
+            float top = childTop + slidingChild.getClipTopAmount();
+            float bottom = childTop + slidingChild.getActualHeight();
             int left = slidingChild.getLeft();
             int right = slidingChild.getRight();
 
@@ -1845,6 +1846,11 @@
         return true;
     }
 
+    public void setScrimAlpha(float progress) {
+        mAmbientState.setScrimAmount(progress);
+        requestChildrenUpdate();
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 602c22b..9a4b798 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -154,6 +154,17 @@
         handleDraggedViews(ambientState, resultState, algorithmState);
         updateDimmedActivated(ambientState, resultState, algorithmState);
         updateClipping(resultState, algorithmState);
+        updateScrimAmount(resultState, algorithmState, ambientState.getScrimAmount());
+    }
+
+    private void updateScrimAmount(StackScrollState resultState,
+            StackScrollAlgorithmState algorithmState, float scrimAmount) {
+        int childCount = algorithmState.visibleChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            View child = algorithmState.visibleChildren.get(i);
+            StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+            childViewState.scrimAmount = scrimAmount;
+        }
     }
 
     private void updateClipping(StackScrollState resultState,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 1ad4acc..02f2cd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -148,6 +148,9 @@
                 // apply dimming
                 child.setDimmed(state.dimmed, false /* animate */);
 
+                // apply scrimming
+                child.setScrimAmount(state.scrimAmount);
+
                 float oldClipTopAmount = child.getClipTopAmount();
                 if (oldClipTopAmount != state.clipTopAmount) {
                     child.setClipTopAmount(state.clipTopAmount);
@@ -223,6 +226,12 @@
         boolean dimmed;
 
         /**
+         * A value between 0 and 1 indicating how much the view should be scrimmed.
+         * 1 means that the notifications will be darkened as much as possible.
+         */
+        float scrimAmount;
+
+        /**
          * The amount which the view should be clipped from the top. This is calculated to
          * perceive consistent shadows.
          */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 225398a..0006dad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -176,6 +176,9 @@
         // start dimmed animation
         child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
 
+        // apply scrimming
+        child.setScrimAmount(viewState.scrimAmount);
+
         if (wasAdded) {
             child.performAddAnimation(delay);
         }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index bc2671011..637061d04 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -624,6 +624,7 @@
         public void onWakeUp() {
             synchronized (mLock) {
                 if (shouldEnableWakeGestureLp()) {
+                    performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
                     mPowerManager.wakeUp(SystemClock.uptimeMillis());
                 }
             }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 7022294..f9c7a78 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -63,6 +63,7 @@
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -240,15 +241,22 @@
         mThread = new Thread(mConnector, NETD_TAG);
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
-        mPhoneStateListener = new PhoneStateListener(
-                SubscriptionManager.DEFAULT_SUB_ID, // FIXME: What Subscription should be used??
+
+        mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUB_ID,
                 mDaemonHandler.getLooper()) {
+            @Override
             public void onDataConnectionRealTimeInfoChanged(
                     DataConnectionRealTimeInfo dcRtInfo) {
+                if (DBG) Slog.d(TAG, "onDataConnectionRealTimeInfoChanged: " + dcRtInfo);
                 notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
                         dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true);
             }
         };
+        TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+        if (tm != null) {
+            tm.listen(mPhoneStateListener,
+                    PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
+        }
 
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 816e022..69262c8 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1328,7 +1328,7 @@
                         + " app=" + app);
             if (app != null && app.thread != null) {
                 try {
-                    app.addPackage(r.appInfo.packageName, mAm.mProcessStats);
+                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                     realStartServiceLocked(r, app, execInFg);
                     return null;
                 } catch (RemoteException e) {
@@ -1883,7 +1883,8 @@
 
                     mPendingServices.remove(i);
                     i--;
-                    proc.addPackage(sr.appInfo.packageName, mAm.mProcessStats);
+                    proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
+                            mAm.mProcessStats);
                     realStartServiceLocked(sr, proc, sr.createdFromFg);
                     didSomething = true;
                 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 34c1ecd..57b56b4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -36,6 +36,9 @@
 import android.app.IAppTask;
 import android.app.admin.DevicePolicyManager;
 import android.appwidget.AppWidgetManager;
+import android.content.DialogInterface.OnClickListener;
+import android.content.res.Resources;
+import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.os.BatteryStats;
 import android.os.PersistableBundle;
@@ -171,8 +174,12 @@
 import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.text.Spannable;
+import android.text.SpannableString;
 import android.text.format.DateUtils;
 import android.text.format.Time;
+import android.text.style.DynamicDrawableSpan;
+import android.text.style.ImageSpan;
 import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
@@ -186,6 +193,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
+import android.widget.TextView;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -570,6 +578,12 @@
     long mLastFullPssTime = SystemClock.uptimeMillis();
 
     /**
+     * If set, the next time we collect PSS data we should do a full collection
+     * with data from native processes and the kernel.
+     */
+    boolean mFullPssPending = false;
+
+    /**
      * This is the process holding what we currently consider to be
      * the "home" activity.
      */
@@ -1158,6 +1172,8 @@
     CompatModeDialog mCompatModeDialog;
     long mLastMemUsageReportTime = 0;
 
+    private LockToAppRequestDialog mLockToAppRequest;
+
     /**
      * Flag whether the current user is a "monkey", i.e. whether
      * the UI is driven by a UI automation tool.
@@ -1801,8 +1817,49 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
             case COLLECT_PSS_BG_MSG: {
-                int i=0, num=0;
                 long start = SystemClock.uptimeMillis();
+                MemInfoReader memInfo = null;
+                synchronized (ActivityManagerService.this) {
+                    if (mFullPssPending) {
+                        mFullPssPending = false;
+                        memInfo = new MemInfoReader();
+                    }
+                }
+                if (memInfo != null) {
+                    updateCpuStatsNow();
+                    long nativeTotalPss = 0;
+                    synchronized (mProcessCpuThread) {
+                        final int N = mProcessCpuTracker.countStats();
+                        for (int j=0; j<N; j++) {
+                            ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(j);
+                            if (st.vsize <= 0 || st.uid >= Process.FIRST_APPLICATION_UID
+                                    || st.uid == Process.SYSTEM_UID) {
+                                // This is definitely an application process; skip it.
+                                continue;
+                            }
+                            synchronized (mPidsSelfLocked) {
+                                if (mPidsSelfLocked.indexOfKey(st.pid) >= 0) {
+                                    // This is one of our own processes; skip it.
+                                    continue;
+                                }
+                            }
+                            nativeTotalPss += Debug.getPss(st.pid, null);
+                        }
+                    }
+                    memInfo.readMemInfo();
+                    synchronized (this) {
+                        if (DEBUG_PSS) Slog.d(TAG, "Collected native and kernel memory in "
+                                + (SystemClock.uptimeMillis()-start) + "ms");
+                        mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
+                                memInfo.getFreeSizeKb(),
+                                memInfo.getSwapTotalSizeKb()-memInfo.getSwapFreeSizeKb(),
+                                memInfo.getBuffersSizeKb()+memInfo.getShmemSizeKb()
+                                        +memInfo.getSlabSizeKb(),
+                                nativeTotalPss);
+                    }
+                }
+
+                int i=0, num=0;
                 long[] tmp = new long[1];
                 do {
                     ProcessRecord proc;
@@ -2176,6 +2233,8 @@
             }
         };
 
+        mLockToAppRequest = new LockToAppRequestDialog(mContext, this);
+
         Watchdog.getInstance().addMonitor(this);
         Watchdog.getInstance().addThread(mHandler);
     }
@@ -2769,7 +2828,7 @@
                 // come up (we have a pid but not yet its thread), so keep it.
                 if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
                 // If this is a new package in the process, add the package to the list
-                app.addPackage(info.packageName, mProcessStats);
+                app.addPackage(info.packageName, info.versionCode, mProcessStats);
                 return app;
             }
 
@@ -2824,7 +2883,7 @@
             }
         } else {
             // If this is a new package in the process, add the package to the list
-            app.addPackage(info.packageName, mProcessStats);
+            app.addPackage(info.packageName, info.versionCode, mProcessStats);
         }
 
         // If the system is not ready yet, then hold off on starting this
@@ -3662,6 +3721,12 @@
             // Keep track of the root activity of the task before we finish it
             TaskRecord tr = r.task;
             ActivityRecord rootR = tr.getRootActivity();
+            // Do not allow task to finish in Lock Task mode.
+            if (tr == mStackSupervisor.mLockTaskModeTask) {
+                if (rootR == r) {
+                    return false;
+                }
+            }
             if (mController != null) {
                 // Find the first activity that is not finishing.
                 ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
@@ -3806,13 +3871,25 @@
     public boolean finishActivityAffinity(IBinder token) {
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            boolean res = false;
-            if (r != null) {
-                res = r.task.stack.finishActivityAffinityLocked(r);
+            try {
+                ActivityRecord r = ActivityRecord.isInStackLocked(token);
+
+                ActivityRecord rootR = r.task.getRootActivity();
+                // Do not allow task to finish in Lock Task mode.
+                if (r.task == mStackSupervisor.mLockTaskModeTask) {
+                    if (rootR == r) {
+                        Binder.restoreCallingIdentity(origId);
+                        return false;
+                    }
+                }
+                boolean res = false;
+                if (r != null) {
+                    res = r.task.stack.finishActivityAffinityLocked(r);
+                }
+                return res;
+            } finally {
+                Binder.restoreCallingIdentity(origId);
             }
-            Binder.restoreCallingIdentity(origId);
-            return res;
         }
     }
 
@@ -6044,7 +6121,11 @@
         if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
             return false;
         }
+        return checkHoldingPermissionsInternalLocked(pm, pi, grantUri, uid, modeFlags, true);
+    }
 
+    private final boolean checkHoldingPermissionsInternalLocked(IPackageManager pm, ProviderInfo pi,
+            GrantUri grantUri, int uid, final int modeFlags, boolean considerUidPermissions) {
         if (pi.applicationInfo.uid == uid) {
             return true;
         } else if (!pi.exported) {
@@ -6055,11 +6136,11 @@
         boolean writeMet = (modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
         try {
             // check if target holds top-level <provider> permissions
-            if (!readMet && pi.readPermission != null
+            if (!readMet && pi.readPermission != null && considerUidPermissions
                     && (pm.checkUidPermission(pi.readPermission, uid) == PERMISSION_GRANTED)) {
                 readMet = true;
             }
-            if (!writeMet && pi.writePermission != null
+            if (!writeMet && pi.writePermission != null && considerUidPermissions
                     && (pm.checkUidPermission(pi.writePermission, uid) == PERMISSION_GRANTED)) {
                 writeMet = true;
             }
@@ -6085,7 +6166,8 @@
                                     + ": match=" + pp.match(path)
                                     + " check=" + pm.checkUidPermission(pprperm, uid));
                             if (pprperm != null) {
-                                if (pm.checkUidPermission(pprperm, uid) == PERMISSION_GRANTED) {
+                                if (considerUidPermissions && pm.checkUidPermission(pprperm, uid)
+                                        == PERMISSION_GRANTED) {
                                     readMet = true;
                                 } else {
                                     allowDefaultRead = false;
@@ -6099,7 +6181,8 @@
                                     + ": match=" + pp.match(path)
                                     + " check=" + pm.checkUidPermission(ppwperm, uid));
                             if (ppwperm != null) {
-                                if (pm.checkUidPermission(ppwperm, uid) == PERMISSION_GRANTED) {
+                                if (considerUidPermissions && pm.checkUidPermission(ppwperm, uid)
+                                        == PERMISSION_GRANTED) {
                                     writeMet = true;
                                 } else {
                                     allowDefaultWrite = false;
@@ -6296,28 +6379,40 @@
             }
         }
 
+        /* There is a special cross user grant if:
+         * - The target is on another user.
+         * - Apps on the current user can access the uri without any uid permissions.
+         * In this case, we grant a uri permission, even if the ContentProvider does not normally
+         * grant uri permissions.
+         */
+        boolean specialCrossUserGrant = UserHandle.getUserId(targetUid) != grantUri.sourceUserId
+                && checkHoldingPermissionsInternalLocked(pm, pi, grantUri, callingUid,
+                modeFlags, false /*without considering the uid permissions*/);
+
         // Second...  is the provider allowing granting of URI permissions?
-        if (!pi.grantUriPermissions) {
-            throw new SecurityException("Provider " + pi.packageName
-                    + "/" + pi.name
-                    + " does not allow granting of Uri permissions (uri "
-                    + grantUri + ")");
-        }
-        if (pi.uriPermissionPatterns != null) {
-            final int N = pi.uriPermissionPatterns.length;
-            boolean allowed = false;
-            for (int i=0; i<N; i++) {
-                if (pi.uriPermissionPatterns[i] != null
-                        && pi.uriPermissionPatterns[i].match(grantUri.uri.getPath())) {
-                    allowed = true;
-                    break;
-                }
-            }
-            if (!allowed) {
+        if (!specialCrossUserGrant) {
+            if (!pi.grantUriPermissions) {
                 throw new SecurityException("Provider " + pi.packageName
                         + "/" + pi.name
-                        + " does not allow granting of permission to path of Uri "
-                        + grantUri);
+                        + " does not allow granting of Uri permissions (uri "
+                        + grantUri + ")");
+            }
+            if (pi.uriPermissionPatterns != null) {
+                final int N = pi.uriPermissionPatterns.length;
+                boolean allowed = false;
+                for (int i=0; i<N; i++) {
+                    if (pi.uriPermissionPatterns[i] != null
+                            && pi.uriPermissionPatterns[i].match(grantUri.uri.getPath())) {
+                        allowed = true;
+                        break;
+                    }
+                }
+                if (!allowed) {
+                    throw new SecurityException("Provider " + pi.packageName
+                            + "/" + pi.name
+                            + " does not allow granting of permission to path of Uri "
+                            + grantUri);
+                }
             }
         }
 
@@ -7642,12 +7737,20 @@
         }
     }
 
-    private void startLockTaskMode(TaskRecord task) {
+    void startLockTaskMode(TaskRecord task) {
         final String pkg;
         synchronized (this) {
             pkg = task.intent.getComponent().getPackageName();
         }
-        if (!isLockTaskAuthorized(pkg)) {
+        boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID;
+        if (!isSystemInitiated && !isLockTaskAuthorized(pkg)) {
+            final TaskRecord taskRecord = task;
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mLockToAppRequest.showLockTaskPrompt(taskRecord);
+                }
+            });
             return;
         }
         long ident = Binder.clearCallingIdentity();
@@ -7659,7 +7762,7 @@
                     if ((mFocusedActivity == null) || (task != mFocusedActivity.task)) {
                         throw new IllegalArgumentException("Invalid task, not in foreground");
                     }
-                    mStackSupervisor.setLockTaskModeLocked(task);
+                    mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated);
                 }
             }
         } finally {
@@ -7704,24 +7807,55 @@
     }
 
     @Override
+    public void startLockTaskModeOnCurrent() throws RemoteException {
+        checkCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS);
+        ActivityRecord r = null;
+        synchronized (this) {
+            r = mStackSupervisor.topRunningActivityLocked();
+        }
+        startLockTaskMode(r.task);
+    }
+
+    @Override
     public void stopLockTaskMode() {
         // Verify that the user matches the package of the intent for the TaskRecord
-        // we are locked to.  This will ensure the same caller for startLockTaskMode and
-        // stopLockTaskMode.
-        try {
-            String pkg = mStackSupervisor.mLockTaskModeTask.intent.getPackage();
-            int uid = mContext.getPackageManager().getPackageUid(pkg,
-                    Binder.getCallingUserHandle().getIdentifier());
-            if (uid != Binder.getCallingUid()) {
-                throw new SecurityException("Invalid uid, expected " + uid);
+        // we are locked to or systtem.  This will ensure the same caller for startLockTaskMode
+        // and stopLockTaskMode.
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SYSTEM_UID) {
+            try {
+                String pkg =
+                        mStackSupervisor.mLockTaskModeTask.intent.getComponent().getPackageName();
+                int uid = mContext.getPackageManager().getPackageUid(pkg,
+                        Binder.getCallingUserHandle().getIdentifier());
+                if (uid != callingUid) {
+                    throw new SecurityException("Invalid uid, expected " + uid);
+                }
+            } catch (NameNotFoundException e) {
+                Log.d(TAG, "stopLockTaskMode " + e);
+                return;
             }
-        } catch (NameNotFoundException e) {
-            Log.d(TAG, "stopLockTaskMode " + e);
-            return;
         }
-        // Stop lock task
-        synchronized (this) {
-            mStackSupervisor.setLockTaskModeLocked(null);
+        long ident = Binder.clearCallingIdentity();
+        try {
+            Log.d(TAG, "stopLockTaskMode");
+            // Stop lock task
+            synchronized (this) {
+                mStackSupervisor.setLockTaskModeLocked(null, false);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public void stopLockTaskModeOnCurrent() throws RemoteException {
+        checkCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS);
+        long ident = Binder.clearCallingIdentity();
+        try {
+            stopLockTaskMode();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -7780,7 +7914,8 @@
                     // to run in multiple processes, because this is actually
                     // part of the framework so doesn't make sense to track as a
                     // separate apk in the process.
-                    app.addPackage(cpi.applicationInfo.packageName, mProcessStats);
+                    app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
+                            mProcessStats);
                 }
                 ensurePackageDexOpt(cpi.applicationInfo.packageName);
             }
@@ -12588,6 +12723,8 @@
             }
         }
 
+        long nativeProcTotalPss = 0;
+
         if (!isCheckinRequest && procs.size() > 1) {
             // If we are showing aggregations, also look for native processes to
             // include so that our aggregations are more accurate.
@@ -12609,6 +12746,7 @@
 
                         final long myTotalPss = mi.getTotalPss();
                         totalPss += myTotalPss;
+                        nativeProcTotalPss += myTotalPss;
 
                         MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
                                 st.name, myTotalPss, st.pid, false);
@@ -12676,6 +12814,15 @@
             }
             MemInfoReader memInfo = new MemInfoReader();
             memInfo.readMemInfo();
+            if (nativeProcTotalPss > 0) {
+                synchronized (this) {
+                    mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
+                            memInfo.getFreeSizeKb(),
+                            memInfo.getSwapTotalSizeKb()-memInfo.getSwapFreeSizeKb(),
+                            memInfo.getBuffersSizeKb()+memInfo.getShmemSizeKb()+memInfo.getSlabSizeKb(),
+                            nativeProcTotalPss);
+                }
+            }
             if (!brief) {
                 if (!isCompact) {
                     pw.print("Total RAM: "); pw.print(memInfo.getTotalSizeKb());
@@ -15456,6 +15603,7 @@
         }
         if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of all procs!  memLowered=" + memLowered);
         mLastFullPssTime = now;
+        mFullPssPending = true;
         mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
         mPendingPssProcesses.clear();
         for (int i=mLruProcesses.size()-1; i>=0; i--) {
@@ -16651,7 +16799,7 @@
                     return true;
                 }
 
-                mStackSupervisor.setLockTaskModeLocked(null);
+                mStackSupervisor.setLockTaskModeLocked(null, false);
 
                 final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
                 if (userInfo == null) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index dd9cae9..0825f2e 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -582,11 +582,6 @@
         }
     }
 
-    boolean isRootActivity() {
-        final ArrayList<ActivityRecord> activities = task.mActivities;
-        return activities.size() == 0 || this == activities.get(0);
-    }
-
     UriPermissionOwner getUriPermissionsLocked() {
         if (uriPermissions == null) {
             uriPermissions = new UriPermissionOwner(service, this);
@@ -1035,11 +1030,11 @@
             return -1;
         }
         final TaskRecord task = r.task;
-        switch (task.mActivities.indexOf(r)) {
-            case -1: return -1;
-            case 0: return task.taskId;
-            default: return onlyRoot ? -1 : task.taskId;
+        final int activityNdx = task.mActivities.indexOf(r);
+        if (activityNdx < 0 || (onlyRoot && activityNdx > task.findEffectiveRootIndex())) {
+            return -1;
         }
+        return task.taskId;
     }
 
     static ActivityRecord isInStackLocked(IBinder token) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 03ce530..fe2a473 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1066,40 +1066,6 @@
         }
     }
 
-    /**
-     * Determine if home should be visible below the passed record.
-     * @param record activity we are querying for.
-     * @return true if home is visible below the passed activity, false otherwise.
-     */
-    boolean isActivityOverHome(ActivityRecord record) {
-        // Start at record and go down, look for either home or a visible fullscreen activity.
-        final TaskRecord recordTask = record.task;
-        for (int taskNdx = mTaskHistory.indexOf(recordTask); taskNdx >= 0; --taskNdx) {
-            TaskRecord task = mTaskHistory.get(taskNdx);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
-            final int startNdx =
-                    task == recordTask ? activities.indexOf(record) : activities.size() - 1;
-            for (int activityNdx = startNdx; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.isHomeActivity()) {
-                    return true;
-                }
-                if (!r.finishing && r.fullscreen) {
-                    // Passed activity is over a fullscreen activity.
-                    return false;
-                }
-            }
-            if (task.mOnTopOfHome) {
-                // Got to the bottom of a task on top of home without finding a visible fullscreen
-                // activity. Home is visible.
-                return true;
-            }
-        }
-        // Got to the bottom of this stack and still don't know. If this is over the home stack
-        // then record is over home. May not work if we ever get more than two layers.
-        return mStackSupervisor.isFrontStack(this);
-    }
-
     private void setVisibile(ActivityRecord r, boolean visible) {
         r.visible = visible;
         mWindowManager.setAppVisibility(r.appToken, visible);
@@ -1954,8 +1920,7 @@
                 // existing activities from other tasks in to it.
                 // If the caller has requested that the target task be
                 // reset, then do so.
-                if ((r.intent.getFlags()
-                        & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+                if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                     resetTaskIfNeededLocked(r, r);
                     doShow = topRunningNonDelayedActivityLocked(null) == r;
                 }
@@ -2048,7 +2013,8 @@
         // the root, we may no longer have the task!).
         final ArrayList<ActivityRecord> activities = task.mActivities;
         final int numActivities = activities.size();
-        for (int i = numActivities - 1; i > 0; --i ) {
+        final int rootActivityNdx = task.findEffectiveRootIndex();
+        for (int i = numActivities - 1; i > rootActivityNdx; --i ) {
             ActivityRecord target = activities.get(i);
 
             final int flags = target.info.flags;
@@ -2207,8 +2173,10 @@
 
         final ArrayList<ActivityRecord> activities = affinityTask.mActivities;
         final int numActivities = activities.size();
-        // Do not operate on the root Activity.
-        for (int i = numActivities - 1; i > 0; --i) {
+        final int rootActivityNdx = affinityTask.findEffectiveRootIndex();
+
+        // Do not operate on or below the effective root Activity.
+        for (int i = numActivities - 1; i > rootActivityNdx; --i) {
             ActivityRecord target = activities.get(i);
 
             final int flags = target.info.flags;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 9264186..4be208b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -79,6 +79,8 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.EventLog;
 import android.util.Slog;
@@ -142,6 +144,8 @@
 
     private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
 
+    private static final String LOCK_TASK_TAG = "Lock-to-App";
+
     /** Status Bar Service **/
     private IBinder mToken = new Binder();
     private IStatusBarService mStatusBarService;
@@ -255,6 +259,10 @@
     /** If non-null then the task specified remains in front and no other tasks may be started
      * until the task exits or #stopLockTaskMode() is called. */
     TaskRecord mLockTaskModeTask;
+    /**
+     * Notifies the user when entering/exiting lock-task.
+     */
+    private LockTaskNotify mLockTaskNotify;
 
     public ActivityStackSupervisor(ActivityManagerService service) {
         mService = service;
@@ -1178,7 +1186,8 @@
                     // to run in multiple processes, because this is actually
                     // part of the framework so doesn't make sense to track as a
                     // separate apk in the process.
-                    app.addPackage(r.info.packageName, mService.mProcessStats);
+                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
+                            mService.mProcessStats);
                 }
                 realStartActivityLocked(r, app, andResume, checkConfig);
                 return;
@@ -3004,7 +3013,7 @@
         return list;
     }
 
-    void setLockTaskModeLocked(TaskRecord task) {
+    void setLockTaskModeLocked(TaskRecord task, boolean showHomeRecents) {
         if (task == null) {
             // Take out of lock task mode if necessary
             if (mLockTaskModeTask != null) {
@@ -3028,6 +3037,7 @@
         lockTaskMsg.obj = mLockTaskModeTask.intent.getComponent().getPackageName();
         lockTaskMsg.arg1 = mLockTaskModeTask.userId;
         lockTaskMsg.what = LOCK_TASK_START_MSG;
+        lockTaskMsg.arg2 = showHomeRecents ? 1 : 0;
         mHandler.sendMessage(lockTaskMsg);
     }
 
@@ -3130,15 +3140,24 @@
                 case LOCK_TASK_START_MSG: {
                     // When lock task starts, we disable the status bars.
                     try {
-                        if (getStatusBarService() != null) {
-                            getStatusBarService().disable
-                                (StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK,
-                                mToken, mService.mContext.getPackageName());
+                        if (mLockTaskNotify == null) {
+                            mLockTaskNotify = new LockTaskNotify(mService.mContext);
                         }
+                        mLockTaskNotify.show(true);
+                        if (getStatusBarService() != null) {
+                            int flags =
+                                    StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK;
+                            if (msg.arg2 != 0) {
+                                flags ^= StatusBarManager.DISABLE_HOME
+                                        | StatusBarManager.DISABLE_RECENT;
+                            }
+                            getStatusBarService().disable(flags, mToken,
+                                    mService.mContext.getPackageName());
+                        }
+                        mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
                         if (getDevicePolicyManager() != null) {
                             getDevicePolicyManager().notifyLockTaskModeChanged(true,
-                                    (String)msg.obj,
-                                    msg.arg1);
+                                    (String)msg.obj, msg.arg1);
                         }
                     } catch (RemoteException ex) {
                         throw new RuntimeException(ex);
@@ -3147,15 +3166,29 @@
                 case LOCK_TASK_END_MSG: {
                     // When lock task ends, we enable the status bars.
                     try {
-                       if (getStatusBarService() != null) {
-                           getStatusBarService().disable
-                               (StatusBarManager.DISABLE_NONE,
-                               mToken, mService.mContext.getPackageName());
-                       }
+                        if (getStatusBarService() != null) {
+                            getStatusBarService().disable(StatusBarManager.DISABLE_NONE, mToken,
+                                    mService.mContext.getPackageName());
+                        }
+                        mWindowManager.reenableKeyguard(mToken);
                         if (getDevicePolicyManager() != null) {
                             getDevicePolicyManager().notifyLockTaskModeChanged(false, null,
                                     msg.arg1);
                         }
+                        if (mLockTaskNotify == null) {
+                            mLockTaskNotify = new LockTaskNotify(mService.mContext);
+                        }
+                        mLockTaskNotify.show(false);
+                        try {
+                            boolean shouldLockKeyguard = Settings.System.getInt(
+                                    mService.mContext.getContentResolver(),
+                                    Settings.System.LOCK_TO_APP_EXIT_LOCKED) != 0;
+                            if (shouldLockKeyguard) {
+                                mWindowManager.lockNow(null);
+                            }
+                        } catch (SettingNotFoundException e) {
+                            // No setting, don't lock.
+                        }
                     } catch (RemoteException ex) {
                         throw new RuntimeException(ex);
                     }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index f403d08..3cbc6e2 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -393,6 +393,20 @@
         }
     }
 
+    public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
+        }
+    }
+
+    public void noteWifiRssiChanged(int newRssi) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiRssiChangedLocked(newRssi);
+        }
+    }
+
     public void noteBluetoothOn() {
         enforceCallingPermission();
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 7b2b04d..cdcc74b 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -887,7 +887,8 @@
                     info.activityInfo.applicationInfo.uid, false);
             if (app != null && app.thread != null) {
                 try {
-                    app.addPackage(info.activityInfo.packageName, mService.mProcessStats);
+                    app.addPackage(info.activityInfo.packageName,
+                            info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
                     processCurBroadcastLocked(r, app);
                     return;
                 } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
new file mode 100644
index 0000000..1997f46
--- /dev/null
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.Message;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import com.android.internal.R;
+
+/**
+ *  Helper to manage showing/hiding a image to notify them that they are entering
+ *  or exiting lock-to-app mode.
+ */
+public class LockTaskNotify {
+    private static final String TAG = "LockTaskNotify";
+
+    private static final int SHOW_LENGTH_MS = 1500;
+
+    private final Context mContext;
+    private final H mHandler;
+
+    private ClingWindowView mClingWindow;
+    private WindowManager mWindowManager;
+    private boolean mIsStarting;
+
+    public LockTaskNotify(Context context) {
+        mContext = context;
+        mHandler = new H();
+        mWindowManager = (WindowManager)
+                mContext.getSystemService(Context.WINDOW_SERVICE);
+    }
+
+    public void show(boolean starting) {
+        mIsStarting = starting;
+        mHandler.obtainMessage(H.SHOW).sendToTarget();
+    }
+
+    public WindowManager.LayoutParams getClingWindowLayoutParams() {
+        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_TOAST,
+                0
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+                ,
+                PixelFormat.TRANSLUCENT);
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        lp.setTitle("LockTaskNotify");
+        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
+        lp.gravity = Gravity.FILL;
+        return lp;
+    }
+
+    public FrameLayout.LayoutParams getImageLayoutParams() {
+        return new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
+    }
+
+    private void handleShow() {
+        mClingWindow = new ClingWindowView(mContext);
+
+        // we will be hiding the nav bar, so layout as if it's already hidden
+        mClingWindow.setSystemUiVisibility(
+                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+              | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+
+        // show the confirmation
+        WindowManager.LayoutParams lp = getClingWindowLayoutParams();
+        mWindowManager.addView(mClingWindow, lp);
+    }
+
+    private void handleHide() {
+        if (mClingWindow != null) {
+            mWindowManager.removeView(mClingWindow);
+            mClingWindow = null;
+        }
+    }
+
+
+    private class ClingWindowView extends FrameLayout {
+        private View mView;
+
+        private Runnable mUpdateLayoutRunnable = new Runnable() {
+            @Override
+            public void run() {
+                if (mView != null && mView.getParent() != null) {
+                    mView.setLayoutParams(getImageLayoutParams());
+                }
+            }
+        };
+
+        private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+                    post(mUpdateLayoutRunnable);
+                }
+            }
+        };
+
+        public ClingWindowView(Context context) {
+            super(context);
+            setClickable(true);
+        }
+
+        @Override
+        public void onAttachedToWindow() {
+            super.onAttachedToWindow();
+
+            DisplayMetrics metrics = new DisplayMetrics();
+            mWindowManager.getDefaultDisplay().getMetrics(metrics);
+
+            int id = R.layout.lock_to_app_exit;
+            if (mIsStarting) {
+                id = R.layout.lock_to_app_enter;
+            }
+            mView = View.inflate(getContext(), id, null);
+
+            addView(mView, getImageLayoutParams());
+
+            mContext.registerReceiver(mReceiver,
+                    new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(H.HIDE), SHOW_LENGTH_MS);
+        }
+
+        @Override
+        public void onDetachedFromWindow() {
+            mContext.unregisterReceiver(mReceiver);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent motion) {
+            Slog.v(TAG, "ClingWindowView.onTouchEvent");
+            return true;
+        }
+    }
+
+    private final class H extends Handler {
+        private static final int SHOW = 1;
+        private static final int HIDE = 2;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case SHOW:
+                    handleShow();
+                    break;
+                case HIDE:
+                    handleHide();
+                    break;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/LockToAppRequestDialog.java b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
new file mode 100644
index 0000000..6e86dff
--- /dev/null
+++ b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
@@ -0,0 +1,87 @@
+
+package com.android.server.am;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.res.Resources;
+import android.graphics.BitmapFactory;
+import android.provider.Settings;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.DynamicDrawableSpan;
+import android.text.style.ImageSpan;
+import android.util.Slog;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+public class LockToAppRequestDialog implements OnClickListener {
+    private static final String TAG = "ActivityManager";
+
+    final private Context mContext;
+    final private ActivityManagerService mService;
+
+    private AlertDialog mDialog;
+    private TaskRecord mRequestedTask;
+
+    public LockToAppRequestDialog(Context context, ActivityManagerService activityManagerService) {
+        mContext = context;
+        mService = activityManagerService;
+    }
+
+    public void showLockTaskPrompt(TaskRecord task) {
+        if (mDialog != null) {
+            mDialog.dismiss();
+            mDialog = null;
+        }
+        mRequestedTask = task;
+
+        final Resources r = Resources.getSystem();
+        final String descriptionString = r.getString(R.string.lock_to_app_description);
+        final SpannableString description =
+                new SpannableString(descriptionString.replace('$', ' '));
+        final ImageSpan imageSpan = new ImageSpan(mContext,
+                BitmapFactory.decodeResource(r, R.drawable.ic_recent),
+                DynamicDrawableSpan.ALIGN_BOTTOM);
+        final int index = descriptionString.indexOf('$');
+        if (index >= 0) {
+            description.setSpan(imageSpan, index, index + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        }
+        mDialog =
+                new AlertDialog.Builder(mContext)
+                        .setTitle(r.getString(R.string.lock_to_app_title))
+                        .setMessage(description)
+                        .setPositiveButton(r.getString(R.string.lock_to_app_positive), this)
+                        .setNegativeButton(r.getString(R.string.lock_to_app_negative), this)
+                        .create();
+
+        mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        mDialog.show();
+
+        // Make icon fit.
+        final TextView msgTxt = (TextView) mDialog.findViewById(R.id.message);
+        final float width = imageSpan.getDrawable().getIntrinsicWidth();
+        final float height = imageSpan.getDrawable().getIntrinsicHeight();
+        final int lineHeight = msgTxt.getLineHeight();
+        imageSpan.getDrawable().setBounds(0, 0, (int) (lineHeight * width / height), lineHeight);
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (DialogInterface.BUTTON_POSITIVE == which) {
+            Slog.d(TAG, "accept lock-to-app request");
+            // Automatically enable if not currently on. (Could be triggered by an app)
+            Settings.System.putInt(mContext.getContentResolver(),
+                    Settings.System.LOCK_TO_APP_ENABLED, 1);
+
+            // Start lock-to-app.
+            mService.startLockTaskMode(mRequestedTask);
+        } else {
+            Slog.d(TAG, "ignore lock-to-app request");
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 8d7d300..2f25bd4 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -53,8 +53,8 @@
     final int userId;           // user of process.
     final String processName;   // name of the process
     // List of packages running in the process
-    final ArrayMap<String, ProcessStats.ProcessState> pkgList
-            = new ArrayMap<String, ProcessStats.ProcessState>();
+    final ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList
+            = new ArrayMap<String, ProcessStats.ProcessStateHolder>();
     IApplicationThread thread;  // the actual proc...  may be null only if
                                 // 'persistent' is true (in which case we
                                 // are in the process of launching the app)
@@ -371,7 +371,7 @@
         uid = _uid;
         userId = UserHandle.getUserId(_uid);
         processName = _processName;
-        pkgList.put(_info.packageName, null);
+        pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.versionCode));
         maxAdj = ProcessList.UNKNOWN_ADJ;
         curRawAdj = setRawAdj = -100;
         curAdj = setAdj = -100;
@@ -398,16 +398,15 @@
                     info.versionCode, processName);
             baseProcessTracker.makeActive();
             for (int i=0; i<pkgList.size(); i++) {
-                ProcessStats.ProcessState ps = pkgList.valueAt(i);
-                if (ps != null && ps != origBase) {
-                    ps.makeInactive();
+                ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
+                if (holder.state != null && holder.state != origBase) {
+                    holder.state.makeInactive();
                 }
-                ps = tracker.getProcessStateLocked(pkgList.keyAt(i), info.uid,
+                holder.state = tracker.getProcessStateLocked(pkgList.keyAt(i), info.uid,
                         info.versionCode, processName);
-                if (ps != baseProcessTracker) {
-                    ps.makeActive();
+                if (holder.state != baseProcessTracker) {
+                    holder.state.makeActive();
                 }
-                pkgList.setValueAt(i, ps);
             }
         }
         thread = _thread;
@@ -424,11 +423,11 @@
             }
             baseProcessTracker = null;
             for (int i=0; i<pkgList.size(); i++) {
-                ProcessStats.ProcessState ps = pkgList.valueAt(i);
-                if (ps != null && ps != origBase) {
-                    ps.makeInactive();
+                ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
+                if (holder.state != null && holder.state != origBase) {
+                    holder.state.makeInactive();
                 }
-                pkgList.setValueAt(i, null);
+                holder.state = null;
             }
         }
     }
@@ -572,17 +571,19 @@
     /*
      *  Return true if package has been added false if not
      */
-    public boolean addPackage(String pkg, ProcessStatsService tracker) {
+    public boolean addPackage(String pkg, int versionCode, ProcessStatsService tracker) {
         if (!pkgList.containsKey(pkg)) {
+            ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
+                    versionCode);
             if (baseProcessTracker != null) {
-                ProcessStats.ProcessState state = tracker.getProcessStateLocked(
-                        pkg, info.uid, info.versionCode, processName);
-                pkgList.put(pkg, state);
-                if (state != baseProcessTracker) {
-                    state.makeActive();
+                holder.state = tracker.getProcessStateLocked(
+                        pkg, info.uid, versionCode, processName);
+                pkgList.put(pkg, holder);
+                if (holder.state != baseProcessTracker) {
+                    holder.state.makeActive();
                 }
             } else {
-                pkgList.put(pkg, null);
+                pkgList.put(pkg, holder);
             }
             return true;
         }
@@ -615,23 +616,26 @@
                     tracker.getMemFactorLocked(), now, pkgList);
             if (N != 1) {
                 for (int i=0; i<N; i++) {
-                    ProcessStats.ProcessState ps = pkgList.valueAt(i);
-                    if (ps != null && ps != baseProcessTracker) {
-                        ps.makeInactive();
+                    ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
+                    if (holder.state != null && holder.state != baseProcessTracker) {
+                        holder.state.makeInactive();
                     }
 
                 }
                 pkgList.clear();
                 ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
                         info.packageName, info.uid, info.versionCode, processName);
-                pkgList.put(info.packageName, ps);
+                ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
+                        info.versionCode);
+                holder.state = ps;
+                pkgList.put(info.packageName, holder);
                 if (ps != baseProcessTracker) {
                     ps.makeActive();
                 }
             }
         } else if (N != 1) {
             pkgList.clear();
-            pkgList.put(info.packageName, null);
+            pkgList.put(info.packageName, new ProcessStats.ProcessStateHolder(info.versionCode));
         }
     }
     
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 14f3ef981..7ec14c29 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -171,10 +171,17 @@
         return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0;
     }
 
+    public void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem,
+            long nativeMem) {
+        mProcessStats.addSysMemUsage(cachedMem, freeMem, zramMem, kernelMem, nativeMem);
+    }
+
     public boolean shouldWriteNowLocked(long now) {
         if (now > (mLastWriteTime+WRITE_PERIOD)) {
             if (SystemClock.elapsedRealtime()
-                    > (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD)) {
+                    > (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD) &&
+                    SystemClock.uptimeMillis()
+                    > (mProcessStats.mTimePeriodStartUptime+ProcessStats.COMMIT_UPTIME_PERIOD)) {
                 mCommitPending = true;
             }
             return true;
@@ -212,6 +219,7 @@
             if (mPendingWrite == null || !mPendingWriteCommitted) {
                 mPendingWrite = Parcel.obtain();
                 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+                mProcessStats.mTimePeriodEndUptime = now;
                 if (commit) {
                     mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
                 }
@@ -439,8 +447,10 @@
         mWriteLock.lock();
         try {
             synchronized (mAm) {
+                long now = SystemClock.uptimeMillis();
                 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
-                mProcessStats.writeToParcel(current, 0);
+                mProcessStats.mTimePeriodEndUptime = now;
+                mProcessStats.writeToParcel(current, now, 0);
             }
             if (historic != null) {
                 ArrayList<String> files = getCommittedFiles(0, false, true);
@@ -470,8 +480,10 @@
             Parcel current = Parcel.obtain();
             long curTime;
             synchronized (mAm) {
+                long now = SystemClock.uptimeMillis();
                 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
-                mProcessStats.writeToParcel(current, 0);
+                mProcessStats.mTimePeriodEndUptime = now;
+                mProcessStats.writeToParcel(current, now, 0);
                 curTime = mProcessStats.mTimePeriodEndRealtime
                         - mProcessStats.mTimePeriodStartRealtime;
             }
@@ -568,8 +580,8 @@
     static private void dumpHelp(PrintWriter pw) {
         pw.println("Process stats (procstats) dump options:");
         pw.println("    [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
-        pw.println("    [--details] [--full-details] [--current] [--hours] [--active]");
-        pw.println("    [--commit] [--reset] [--clear] [--write] [-h] [<package.name>]");
+        pw.println("    [--details] [--full-details] [--current] [--hours N] [--last N]");
+        pw.println("    [--active] [--commit] [--reset] [--clear] [--write] [-h] [<package.name>]");
         pw.println("  --checkin: perform a checkin: print and delete old committed states.");
         pw.println("  --c: print only state in checkin format.");
         pw.println("  --csv: output data suitable for putting in a spreadsheet.");
@@ -581,6 +593,7 @@
         pw.println("  --full-details: dump all timing and active state details.");
         pw.println("  --current: only dump current state.");
         pw.println("  --hours: aggregate over about N last hours.");
+        pw.println("  --last: only show the last committed stats at index N (starting at 1).");
         pw.println("  --active: only show currently active processes/services.");
         pw.println("  --commit: commit current stats to disk and reset to start new stats.");
         pw.println("  --reset: reset current stats, without committing.");
@@ -621,6 +634,7 @@
         boolean dumpFullDetails = false;
         boolean dumpAll = false;
         int aggregateHours = 0;
+        int lastIndex = 0;
         boolean activeOnly = false;
         String reqPackage = null;
         boolean csvSepScreenStats = false;
@@ -705,6 +719,20 @@
                         dumpHelp(pw);
                         return;
                     }
+                } else if ("--last".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("Error: argument required for --last");
+                        dumpHelp(pw);
+                        return;
+                    }
+                    try {
+                        lastIndex = Integer.parseInt(args[i]);
+                    } catch (NumberFormatException e) {
+                        pw.println("Error: --last argument not an int -- " + args[i]);
+                        dumpHelp(pw);
+                        return;
+                    }
                 } else if ("--active".equals(arg)) {
                     activeOnly = true;
                     currentOnly = true;
@@ -818,6 +846,43 @@
             dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact,
                     dumpDetails, dumpFullDetails, dumpAll, activeOnly);
             return;
+        } else if (lastIndex > 0) {
+            pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":");
+            ArrayList<String> files = getCommittedFiles(0, false, true);
+            if (lastIndex >= files.size()) {
+                pw.print("Only have "); pw.print(files.size()); pw.println(" data sets");
+                return;
+            }
+            AtomicFile file = new AtomicFile(new File(files.get(lastIndex)));
+            ProcessStats processStats = new ProcessStats(false);
+            readLocked(processStats, file);
+            if (processStats.mReadError != null) {
+                if (isCheckin || isCompact) pw.print("err,");
+                pw.print("Failure reading "); pw.print(files.get(lastIndex));
+                pw.print("; "); pw.println(processStats.mReadError);
+                return;
+            }
+            String fileStr = file.getBaseFile().getPath();
+            boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
+            if (isCheckin || isCompact) {
+                // Don't really need to lock because we uniquely own this object.
+                processStats.dumpCheckinLocked(pw, reqPackage);
+            } else {
+                pw.print("COMMITTED STATS FROM ");
+                pw.print(processStats.mTimePeriodStartClockStr);
+                if (checkedIn) pw.print(" (checked in)");
+                pw.println(":");
+                if (dumpDetails || dumpFullDetails) {
+                    processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll,
+                            activeOnly);
+                    if (dumpAll) {
+                        pw.print("  mFile="); pw.println(mFile.getBaseFile());
+                    }
+                } else {
+                    processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
+                }
+            }
+            return;
         }
 
         boolean sepNeeded = false;
@@ -859,7 +924,7 @@
                                 // Always dump summary here, dumping all details is just too
                                 // much crud.
                                 if (dumpFullDetails) {
-                                    mProcessStats.dumpLocked(pw, reqPackage, now, false, false,
+                                    processStats.dumpLocked(pw, reqPackage, now, false, false,
                                             activeOnly);
                                 } else {
                                     processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 1cde41f..e9afc36 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -27,7 +27,6 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.Slog;
@@ -57,11 +56,12 @@
     private static final String ATTR_ONTOPOFHOME = "on_top_of_home";
     private static final String ATTR_LASTDESCRIPTION = "last_description";
     private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
+    private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
 
     private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
 
     final int taskId;       // Unique identifier for this task.
-    final String affinity;  // The affinity name for this task, or null.
+    String affinity;        // The affinity name for this task, or null.
     final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
     final IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
     Intent intent;          // The original intent that started the task.
@@ -111,13 +111,19 @@
      * Display.DEFAULT_DISPLAY. */
     boolean mOnTopOfHome = false;
 
+    /** If original intent did not allow relinquishing task identity, save that information */
+    boolean mNeverRelinquishIdentity = true;
+
+    // Used in the unique case where we are clearing the task in order to reuse it. In that case we
+    // do not want to delete the stack when the task goes empty.
+    boolean mReuseTask = false;
+
     final ActivityManagerService mService;
 
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
         mService = service;
         taskId = _taskId;
-        affinity = info.taskAffinity;
         voiceSession = _voiceSession;
         voiceInteractor = _voiceInteractor;
         setIntent(_intent, info);
@@ -128,7 +134,7 @@
             String _affinity, ComponentName _realActivity, ComponentName _origActivity,
             boolean _rootWasReset, boolean _askedCompatMode, int _taskType, boolean _onTopOfHome,
             int _userId, String _lastDescription, ArrayList<ActivityRecord> activities,
-            long lastTimeMoved) {
+            long lastTimeMoved, boolean neverRelinquishIdentity) {
         mService = service;
         taskId = _taskId;
         intent = _intent;
@@ -146,6 +152,7 @@
         lastDescription = _lastDescription;
         mActivities = activities;
         mLastTimeMoved = lastTimeMoved;
+        mNeverRelinquishIdentity = neverRelinquishIdentity;
     }
 
     void touchActiveTime() {
@@ -157,6 +164,14 @@
     }
 
     void setIntent(Intent _intent, ActivityInfo info) {
+        if (intent == null) {
+            mNeverRelinquishIdentity =
+                    (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+        } else if (mNeverRelinquishIdentity) {
+            return;
+        }
+
+        affinity = info.taskAffinity;
         stringName = null;
 
         if (info.targetActivity == null) {
@@ -271,6 +286,11 @@
                 foundFront = true;
             }
         }
+        if (!foundFront && numActivities > 0) {
+            // All activities of this task are finishing. As we ought to have a frontOfTask
+            // activity, make the bottom activity front.
+            mActivities.get(0).frontOfTask = true;
+        }
     }
 
     /**
@@ -282,6 +302,7 @@
 
         mActivities.remove(newTop);
         mActivities.add(newTop);
+        updateEffectiveIntent();
 
         setFrontOfTask();
     }
@@ -311,6 +332,7 @@
             r.mActivityType = taskType;
         }
         mActivities.add(index, r);
+        updateEffectiveIntent();
         if (r.isPersistable()) {
             mService.notifyTaskPersisterLocked(this, false);
         }
@@ -325,7 +347,11 @@
         if (r.isPersistable()) {
             mService.notifyTaskPersisterLocked(this, false);
         }
-        return mActivities.size() == 0;
+        if (mActivities.isEmpty()) {
+            return !mReuseTask;
+        }
+        updateEffectiveIntent();
+        return false;
     }
 
     boolean autoRemoveFromRecents() {
@@ -366,7 +392,9 @@
      * Completely remove all activities associated with an existing task.
      */
     final void performClearTaskLocked() {
+        mReuseTask = true;
         performClearTaskAtIndexLocked(0);
+        mReuseTask = false;
     }
 
     /**
@@ -579,12 +607,19 @@
         // utility activities.
         int activityNdx;
         final int numActivities = mActivities.size();
+        final boolean relinquish = numActivities == 0 ? false :
+                (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0;
         for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
                 ++activityNdx) {
             final ActivityRecord r = mActivities.get(activityNdx);
+            if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+                // This will be the top activity for determining taskDescription. Pre-inc to
+                // overcome initial decrement below.
+                ++activityNdx;
+                break;
+            }
             if (r.intent != null &&
-                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
-                            != 0) {
+                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
                 break;
             }
         }
@@ -615,6 +650,27 @@
         }
     }
 
+    int findEffectiveRootIndex() {
+        int activityNdx;
+        final int topActivityNdx = mActivities.size() - 1;
+        for (activityNdx = 0; activityNdx < topActivityNdx; ++activityNdx) {
+            final ActivityRecord r = mActivities.get(activityNdx);
+            if (r.finishing) {
+                continue;
+            }
+            if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+                break;
+            }
+        }
+        return activityNdx;
+    }
+
+    void updateEffectiveIntent() {
+        final int effectiveRootIndex = findEffectiveRootIndex();
+        final ActivityRecord r = mActivities.get(effectiveRootIndex);
+        setIntent(r.intent, r.info);
+    }
+
     void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
         Slog.i(TAG, "Saving task=" + this);
 
@@ -634,6 +690,7 @@
         out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
         out.attribute(null, ATTR_ONTOPOFHOME, String.valueOf(mOnTopOfHome));
         out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
+        out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
         if (lastDescription != null) {
             out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
         }
@@ -684,6 +741,7 @@
         int userId = 0;
         String lastDescription = null;
         long lastTimeOnTop = 0;
+        boolean neverRelinquishIdentity = true;
         int taskId = -1;
         final int outerDepth = in.getDepth();
 
@@ -714,6 +772,8 @@
                 lastDescription = attrValue;
             } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
                 lastTimeOnTop = Long.valueOf(attrValue);
+            } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
+                neverRelinquishIdentity = Boolean.valueOf(attrValue);
             } else {
                 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
             }
@@ -748,7 +808,7 @@
         final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
                 affinityIntent, affinity, realActivity, origActivity, rootHasReset,
                 askedCompatMode, taskType, onTopOfHome, userId, lastDescription, activities,
-                lastTimeOnTop);
+                lastTimeOnTop, neverRelinquishIdentity);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
             final ActivityRecord r = activities.get(activityNdx);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index e61bad9..420304e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -78,7 +78,7 @@
      */
     void deviceSelect(int targetAddress, IHdmiControlCallback callback) {
         assertRunOnServiceThread();
-        HdmiCecDeviceInfo targetDevice = mService.getDeviceInfo(targetAddress);
+        HdmiCecDeviceInfo targetDevice = getDeviceInfo(targetAddress);
         if (targetDevice == null) {
             invokeCallback(callback, HdmiCec.RESULT_TARGET_NOT_AVAILABLE);
             return;
@@ -253,20 +253,35 @@
         mDeviceInfos.clear();
     }
 
+    void changeSystemAudioMode(boolean enabled, IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        HdmiCecDeviceInfo avr = getAvrDeviceInfo();
+        if (avr == null) {
+            invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+            return;
+        }
+
+        addAndStartAction(
+                new SystemAudioActionFromTv(this, avr.getLogicalAddress(), enabled, callback));
+   }
+
+    boolean canChangeSystemAudioMode() {
+        // TODO: once have immutable device info, test whether avr info exists or not.
+        return false;
+    }
+
     void setSystemAudioMode(boolean on) {
         synchronized (mLock) {
             if (on != mSystemAudioMode) {
                 mSystemAudioMode = on;
                 // TODO: Need to set the preference for SystemAudioMode.
-                // TODO: Need to handle the notification of changing the mode and
-                // to identify the notification should be handled in the service or TvSettings.
+                mService.announceSystemAudioModeChange(on);
             }
         }
     }
 
     boolean getSystemAudioMode() {
         synchronized (mLock) {
-            assertRunOnServiceThread();
             return mSystemAudioMode;
         }
     }
@@ -336,7 +351,7 @@
             return false;
         }
         SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this,
-                message.getSource(), HdmiUtils.parseCommandParamSystemAudioStatus(message));
+                message.getSource(), HdmiUtils.parseCommandParamSystemAudioStatus(message), null);
         addAndStartAction(action);
         return true;
     }
@@ -458,8 +473,11 @@
     final void addCecDevice(HdmiCecDeviceInfo info) {
         assertRunOnServiceThread();
         addDeviceInfo(info);
+        if (info.getLogicalAddress() == mAddress) {
+            // The addition of TV device itself should not be notified.
+            return;
+        }
         mService.invokeDeviceEventListeners(info, true);
-        // TODO: announce new device detection.
     }
 
     /**
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 050ba46..7774878 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -27,6 +27,7 @@
 import android.hardware.hdmi.IHdmiControlService;
 import android.hardware.hdmi.IHdmiDeviceEventListener;
 import android.hardware.hdmi.IHdmiHotplugEventListener;
+import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -113,6 +114,14 @@
     private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords =
             new ArrayList<>();
 
+    // List of listeners registered by callers that want to get notified of
+    // system audio mode changes.
+    private final ArrayList<IHdmiSystemAudioModeChangeListener>
+            mSystemAudioModeChangeListeners = new ArrayList<>();
+    // List of records for system audio mode change to handle the the caller killed in action.
+    private final ArrayList<SystemAudioModeChangeListenerRecord>
+            mSystemAudioModeChangeListenerRecords = new ArrayList<>();
+
     // Handler used to run a task in service thread.
     private final Handler mHandler = new Handler();
 
@@ -158,6 +167,7 @@
         // A container for [Logical Address, Local device info].
         final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>();
         final SparseIntArray finished = new SparseIntArray();
+        mCecController.clearLogicalAddress();
         for (int type : deviceTypes) {
             final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type);
             localDevice.init();
@@ -189,7 +199,7 @@
         for (int i = 0; i < devices.size(); ++i) {
             int address = devices.keyAt(i);
             HdmiCecLocalDevice device = devices.valueAt(i);
-            device.onAddressAllocated(address);
+            device.handleAddressAllocated(address);
         }
     }
 
@@ -446,6 +456,12 @@
         // TODO: Hook up with AudioManager.
     }
 
+    void announceSystemAudioModeChange(boolean enabled) {
+        for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) {
+            invokeSystemAudioModeChange(listener, enabled);
+        }
+    }
+
     private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) {
         // TODO: find better name instead of model name.
         String displayName = Build.MODEL;
@@ -479,7 +495,7 @@
         }
 
         @Override
-            public void binderDied() {
+        public void binderDied() {
             synchronized (mLock) {
                 mDeviceEventListenerRecords.remove(this);
                 mDeviceEventListeners.remove(mListener);
@@ -487,6 +503,22 @@
         }
     }
 
+    private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient {
+        private IHdmiSystemAudioModeChangeListener mListener;
+
+        public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mSystemAudioModeChangeListenerRecords.remove(this);
+                mSystemAudioModeChangeListeners.remove(mListener);
+            }
+        }
+    }
+
     private void enforceAccessPermission() {
         getContext().enforceCallingOrSelfPermission(PERMISSION, TAG);
     }
@@ -604,7 +636,7 @@
             enforceAccessPermission();
             runOnServiceThread(new Runnable() {
                 @Override
-                    public void run() {
+                public void run() {
                     HdmiControlService.this.addDeviceEventListener(listener);
                 }
             });
@@ -615,6 +647,57 @@
             enforceAccessPermission();
             return mPortInfo;
         }
+
+        @Override
+        public boolean canChangeSystemAudioMode() {
+            enforceAccessPermission();
+            HdmiCecLocalDeviceTv tv = tv();
+            if (tv == null) {
+                return false;
+            }
+            return tv.canChangeSystemAudioMode();
+        }
+
+        @Override
+        public boolean getSystemAudioMode() {
+            enforceAccessPermission();
+            HdmiCecLocalDeviceTv tv = tv();
+            if (tv == null) {
+                return false;
+            }
+            return tv.getSystemAudioMode();
+        }
+
+        @Override
+        public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiCecLocalDeviceTv tv = tv();
+                    if (tv == null) {
+                        Slog.w(TAG, "Local tv device not available");
+                        invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+                        return;
+                    }
+                    tv.changeSystemAudioMode(enabled, callback);
+                }
+            });
+        }
+
+        @Override
+        public void addSystemAudioModeChangeListener(
+                final IHdmiSystemAudioModeChangeListener listener) {
+            enforceAccessPermission();
+            HdmiControlService.this.addSystemAudioModeChangeListner(listener);
+        }
+
+        @Override
+        public void removeSystemAudioModeChangeListener(
+                final IHdmiSystemAudioModeChangeListener listener) {
+            enforceAccessPermission();
+            HdmiControlService.this.removeSystemAudioModeChangeListener(listener);
+        }
     }
 
     private void oneTouchPlay(final IHdmiControlCallback callback) {
@@ -692,6 +775,35 @@
         }
     }
 
+    private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) {
+        SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord(
+                listener);
+        try {
+            listener.asBinder().linkToDeath(record, 0);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Listener already died");
+            return;
+        }
+        synchronized (mLock) {
+            mSystemAudioModeChangeListeners.add(listener);
+            mSystemAudioModeChangeListenerRecords.add(record);
+        }
+    }
+
+    private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) {
+        synchronized (mLock) {
+            for (SystemAudioModeChangeListenerRecord record :
+                    mSystemAudioModeChangeListenerRecords) {
+                if (record.mListener.asBinder() == listener) {
+                    listener.asBinder().unlinkToDeath(record, 0);
+                    mSystemAudioModeChangeListenerRecords.remove(record);
+                    break;
+                }
+            }
+            mSystemAudioModeChangeListeners.remove(listener);
+        }
+    }
+
     private void invokeCallback(IHdmiControlCallback callback, int result) {
         try {
             callback.onComplete(result);
@@ -700,6 +812,15 @@
         }
     }
 
+    private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener,
+            boolean enabled) {
+        try {
+            listener.onStatusChanged(enabled);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Invoking callback failed:" + e);
+        }
+    }
+
     private void announceHotplugEvent(int portId, boolean connected) {
         HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected);
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index e48b0dc..959a38e 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -16,8 +16,12 @@
 
 package com.android.server.hdmi;
 
+import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiCec;
 import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
 
 /**
  * Base feature action class for SystemAudioActionFromTv and SystemAudioActionFromAvr.
@@ -28,9 +32,6 @@
     // State in which waits for <SetSystemAudioMode>.
     private static final int STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE = 1;
 
-    // State in which waits for <ReportAudioStatus>.
-    private static final int STATE_WAIT_FOR_REPORT_AUDIO_STATUS = 2;
-
     private static final int MAX_SEND_RETRY_COUNT = 2;
 
     private static final int ON_TIMEOUT_MS = 5000;
@@ -42,6 +43,8 @@
     // The target audio status of the action, whether to enable the system audio mode or not.
     protected boolean mTargetAudioStatus;
 
+    @Nullable private final IHdmiControlCallback mCallback;
+
     private int mSendRetryCount = 0;
 
     /**
@@ -50,13 +53,16 @@
      * @param source {@link HdmiCecLocalDevice} instance
      * @param avrAddress logical address of AVR device
      * @param targetStatus Whether to enable the system audio mode or not
+     * @param callback callback interface to be notified when it's done
      * @throw IllegalArugmentException if device type of sourceAddress and avrAddress is invalid
      */
-    SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus) {
+    SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus,
+            IHdmiControlCallback callback) {
         super(source);
         HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
         mAvrLogicalAddress = avrAddress;
         mTargetAudioStatus = targetStatus;
+        mCallback = callback;
     }
 
     protected void sendSystemAudioModeRequest() {
@@ -72,7 +78,7 @@
                     addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS);
                 } else {
                     setSystemAudioMode(false);
-                    finish();
+                    finishWithCallback(HdmiCec.RESULT_EXCEPTION);
                 }
             }
         });
@@ -82,7 +88,7 @@
         if (!mTargetAudioStatus  // Don't retry for Off case.
                 || mSendRetryCount++ >= MAX_SEND_RETRY_COUNT) {
             setSystemAudioMode(false);
-            finish();
+            finishWithCallback(HdmiCec.RESULT_TIMEOUT);
             return;
         }
         sendSystemAudioModeRequest();
@@ -92,39 +98,6 @@
         tv().setSystemAudioMode(mode);
     }
 
-    protected void sendGiveAudioStatus() {
-        HdmiCecMessage command = HdmiCecMessageBuilder.buildGiveAudioStatus(getSourceAddress(),
-                mAvrLogicalAddress);
-        sendCommand(command, new HdmiControlService.SendMessageCallback() {
-            @Override
-            public void onSendCompleted(int error) {
-                if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
-                    mState = STATE_WAIT_FOR_REPORT_AUDIO_STATUS;
-                    addTimer(mState, TIMEOUT_MS);
-                } else {
-                    handleSendGiveAudioStatusFailure();
-                }
-            }
-        });
-    }
-
-    private void handleSendGiveAudioStatusFailure() {
-        // TODO: Notify the failure status.
-
-        int uiCommand = tv().getSystemAudioMode()
-                ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION  // SystemAudioMode: ON
-                : HdmiConstants.UI_COMMAND_MUTE_FUNCTION;           // SystemAudioMode: OFF
-        sendUserControlPressedAndReleased(uiCommand);
-        finish();
-    }
-
-    private void sendUserControlPressedAndReleased(int uiCommand) {
-        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
-                getSourceAddress(), mAvrLogicalAddress, uiCommand));
-        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
-                getSourceAddress(), mAvrLogicalAddress));
-    }
-
     @Override
     final boolean processCommand(HdmiCecMessage cmd) {
         switch (mState) {
@@ -137,36 +110,23 @@
                 boolean receivedStatus = HdmiUtils.parseCommandParamSystemAudioStatus(cmd);
                 if (receivedStatus == mTargetAudioStatus) {
                     setSystemAudioMode(receivedStatus);
-                    sendGiveAudioStatus();
+                    startAudioStatusAction();
+                    return true;
                 } else {
                     // Unexpected response, consider the request is newly initiated by AVR.
                     // To return 'false' will initiate new SystemAudioActionFromAvr by the control
                     // service.
-                    finish();
+                    finishWithCallback(HdmiCec.RESULT_EXCEPTION);
                     return false;
                 }
-                return true;
-
-            case STATE_WAIT_FOR_REPORT_AUDIO_STATUS:
-                // TODO: Handle <FeatureAbort> of <GiveAudioStatus>
-                if (cmd.getOpcode() != HdmiCec.MESSAGE_REPORT_AUDIO_STATUS
-                        || !HdmiUtils.checkCommandSource(cmd, mAvrLogicalAddress, TAG)) {
-                    return false;
-                }
-                byte[] params = cmd.getParams();
-                if (params.length > 0) {
-                    boolean mute = (params[0] & 0x80) == 0x80;
-                    int volume = params[0] & 0x7F;
-                    tv().setAudioStatus(mute, volume);
-                    if (mTargetAudioStatus && mute || !mTargetAudioStatus && !mute) {
-                        // Toggle AVR's mute status to match with the system audio status.
-                        sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
-                    }
-                }
-                finish();
-                return true;
+            default:
+                return false;
         }
-        return false;
+    }
+
+    protected void startAudioStatusAction() {
+        addAndStartAction(new SystemAudioStatusAction(tv(), mAvrLogicalAddress, mCallback));
+        finish();
     }
 
     protected void removeSystemAudioActionInProgress() {
@@ -183,9 +143,19 @@
             case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
                 handleSendSystemAudioModeRequestTimeout();
                 return;
-            case STATE_WAIT_FOR_REPORT_AUDIO_STATUS:
-                handleSendGiveAudioStatusFailure();
-                return;
         }
     }
+
+    // TODO: if IHdmiControlCallback is general to other FeatureAction,
+    //       move it into FeatureAction.
+    protected void finishWithCallback(int returnCode) {
+        if (mCallback != null) {
+            try {
+                mCallback.onComplete(returnCode);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to invoke callback.", e);
+            }
+        }
+        finish();
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
index 3907b71..9d34589 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
@@ -17,6 +17,7 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.IHdmiControlCallback;
 
 /**
  * Feature action that handles System Audio initiated by AVR devices.
@@ -28,11 +29,12 @@
      * @param source {@link HdmiCecLocalDevice} instance
      * @param avrAddress logical address of AVR device
      * @param targetStatus Whether to enable the system audio mode or not
+     * @param callback callback interface to be notified when it's done
      * @throw IllegalArugmentException if device type of tvAddress and avrAddress is invalid
      */
     SystemAudioActionFromAvr(HdmiCecLocalDevice source, int avrAddress,
-            boolean targetStatus) {
-        super(source, avrAddress, targetStatus);
+            boolean targetStatus, IHdmiControlCallback callback) {
+        super(source, avrAddress, targetStatus, callback);
         HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
     }
 
@@ -45,7 +47,7 @@
 
     private void handleSystemAudioActionFromAvr() {
         if (mTargetAudioStatus == tv().getSystemAudioMode()) {
-            finish();
+            finishWithCallback(HdmiCec.RESULT_SUCCESS);
             return;
         }
         if (tv().isInPresetInstallationMode()) {
@@ -59,10 +61,10 @@
         // TODO: Stop the action for System Audio Mode initialization if it is running.
         if (mTargetAudioStatus) {
             setSystemAudioMode(true);
-            sendGiveAudioStatus();
+            startAudioStatusAction();
         } else {
             setSystemAudioMode(false);
-            finish();
+            finishWithCallback(HdmiCec.RESULT_SUCCESS);
         }
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
index e0c4ff4..2d8f3fc 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
@@ -17,6 +17,7 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.IHdmiControlCallback;
 
 
 /**
@@ -29,11 +30,12 @@
      * @param sourceAddress {@link HdmiCecLocalDevice} instance
      * @param avrAddress logical address of AVR device
      * @param targetStatus Whether to enable the system audio mode or not
+     * @param callback callback interface to be notified when it's done
      * @throw IllegalArugmentException if device type of tvAddress is invalid
      */
     SystemAudioActionFromTv(HdmiCecLocalDevice sourceAddress, int avrAddress,
-            boolean targetStatus) {
-        super(sourceAddress, avrAddress, targetStatus);
+            boolean targetStatus, IHdmiControlCallback callback) {
+        super(sourceAddress, avrAddress, targetStatus, callback);
         HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
     }
 
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index e4d82ef..845eaa9 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -77,14 +77,14 @@
         // If the last setting is system audio, turn on system audio whatever AVR status is.
         if (tv().getSystemAudioMode()) {
             if (canChangeSystemAudio()) {
-                addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true));
+                addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true, null));
             }
         } else {
             // If the last setting is non-system audio, turn off system audio mode
             // and update system audio status (volume or mute).
             tv().setSystemAudioMode(false);
             if (canChangeSystemAudio()) {
-                addAndStartAction(new SystemAudioStatusAction(tv(), mAvrAddress));
+                addAndStartAction(new SystemAudioStatusAction(tv(), mAvrAddress, null));
             }
         }
         finish();
@@ -106,7 +106,7 @@
     private void handleSystemAudioModeStatusTimeout() {
         if (tv().getSystemAudioMode()) {
             if (canChangeSystemAudio()) {
-                addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true));
+                addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true, null));
             }
         } else {
             tv().setSystemAudioMode(false);
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index 75e4fef..89206a7 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -16,8 +16,11 @@
 
 package com.android.server.hdmi;
 
+import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiCec;
 import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
 import android.util.Slog;
 
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
@@ -25,7 +28,6 @@
 /**
  * Action to update audio status (volume or mute) of audio amplifier
  */
-// TODO: refactor SystemAudioMode so that it uses this class instead of internal state.
 final class SystemAudioStatusAction extends FeatureAction {
     private static final String TAG = "SystemAudioStatusAction";
 
@@ -33,10 +35,13 @@
     private static final int STATE_WAIT_FOR_REPORT_AUDIO_STATUS = 1;
 
     private final int mAvrAddress;
+    @Nullable private final IHdmiControlCallback mCallback;
 
-    SystemAudioStatusAction(HdmiCecLocalDevice source, int avrAddress) {
+    SystemAudioStatusAction(HdmiCecLocalDevice source, int avrAddress,
+            IHdmiControlCallback callback) {
         super(source);
         mAvrAddress = avrAddress;
+        mCallback = callback;
     }
 
     @Override
@@ -68,7 +73,9 @@
                 ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION  // SystemAudioMode: ON
                 : HdmiConstants.UI_COMMAND_MUTE_FUNCTION;           // SystemAudioMode: OFF
         sendUserControlPressedAndReleased(uiCommand);
-        finish();
+
+        // Still return SUCCESS to callback.
+        finishWithCallback(HdmiCec.RESULT_SUCCESS);
     }
 
     private void sendUserControlPressedAndReleased(int uiCommand) {
@@ -104,7 +111,7 @@
                 // Toggle AVR's mute status to match with the system audio status.
                 sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
             }
-            finish();
+            finishWithCallback(HdmiCec.RESULT_SUCCESS);
         } else {
             Slog.e(TAG, "Invalid <Report Audio Status> message:" + cmd);
             handleSendGiveAudioStatusFailure();
@@ -112,6 +119,17 @@
         }
     }
 
+    private void finishWithCallback(int returnCode) {
+        if (mCallback != null) {
+            try {
+                mCallback.onComplete(returnCode);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to invoke callback.", e);
+            }
+        }
+        finish();
+    }
+
     @Override
     void handleTimerEvent(int state) {
         if (mState != state) {
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 15a6b25..53337c4 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -203,7 +203,8 @@
     @Override
     public String toString() {
         return String.valueOf(hashCode()).substring(0, 3) + ".."
-                + ":[" + job.getService().getPackageName() + ",jId=" + job.getId()
+                + ":[" + job.getService()
+                + ",jId=" + job.getId()
                 + ",R=(" + earliestRunTimeElapsedMillis + "," + latestRunTimeElapsedMillis + ")"
                 + ",N=" + job.getNetworkCapabilities() + ",C=" + job.isRequireCharging()
                 + ",I=" + job.isRequireDeviceIdle() + ",F=" + numFailures
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 9d61493..1264741 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -17,6 +17,8 @@
 package com.android.server.media;
 
 import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.media.routeprovider.RouteRequest;
@@ -25,7 +27,6 @@
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
 import android.media.session.MediaController;
-import android.media.session.RemoteVolumeProvider;
 import android.media.session.RouteCommand;
 import android.media.session.RouteInfo;
 import android.media.session.RouteOptions;
@@ -34,9 +35,11 @@
 import android.media.session.MediaSessionInfo;
 import android.media.session.RouteInterface;
 import android.media.session.PlaybackState;
+import android.media.session.ParcelableVolumeInfo;
 import android.media.AudioManager;
 import android.media.MediaMetadata;
 import android.media.Rating;
+import android.media.VolumeProvider;
 import android.os.Bundle;
 import android.os.DeadObjectException;
 import android.os.Handler;
@@ -107,6 +110,7 @@
     // TODO define a RouteState class with relevant info
     private int mRouteState;
     private long mFlags;
+    private ComponentName mMediaButtonReceiver;
 
     // TransportPerformer fields
 
@@ -117,9 +121,10 @@
     // End TransportPerformer fields
 
     // Volume handling fields
-    private int mPlaybackType = MediaSession.VOLUME_TYPE_LOCAL;
+    private AudioManager mAudioManager;
+    private int mVolumeType = MediaSession.VOLUME_TYPE_LOCAL;
     private int mAudioStream = AudioManager.STREAM_MUSIC;
-    private int mVolumeControlType = RemoteVolumeProvider.VOLUME_CONTROL_ABSOLUTE;
+    private int mVolumeControlType = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
     private int mMaxVolume = 0;
     private int mCurrentVolume = 0;
     // End volume handling fields
@@ -140,6 +145,7 @@
         mSessionCb = new SessionCb(cb);
         mService = service;
         mHandler = new MessageHandler(handler.getLooper());
+        mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
     }
 
     /**
@@ -187,6 +193,10 @@
         return mSessionInfo;
     }
 
+    public ComponentName getMediaButtonReceiver() {
+        return mMediaButtonReceiver;
+    }
+
     /**
      * Get this session's flags.
      *
@@ -265,20 +275,42 @@
      *
      * @param delta The amount to adjust the volume by.
      */
-    public void adjustVolumeBy(int delta) {
-        if (mVolumeControlType == RemoteVolumeProvider.VOLUME_CONTROL_FIXED) {
-            // Nothing to do, the volume cannot be changed
-            return;
+    public void adjustVolumeBy(int delta, int flags) {
+        if (mVolumeType == MediaSession.VOLUME_TYPE_LOCAL) {
+            if (delta == 0) {
+                mAudioManager.adjustStreamVolume(mAudioStream, delta, flags);
+            } else {
+                int direction = 0;
+                int steps = delta;
+                if (delta > 0) {
+                    direction = 1;
+                } else if (delta < 0) {
+                    direction = -1;
+                    steps = -delta;
+                }
+                for (int i = 0; i < steps; i++) {
+                    mAudioManager.adjustStreamVolume(mAudioStream, direction, flags);
+                }
+            }
+        } else {
+            if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
+                // Nothing to do, the volume cannot be changed
+                return;
+            }
+            mSessionCb.adjustVolumeBy(delta);
         }
-        mSessionCb.adjustVolumeBy(delta);
     }
 
-    public void setVolumeTo(int value) {
-        if (mVolumeControlType != RemoteVolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
-            // Nothing to do. The volume can't be set directly.
-            return;
+    public void setVolumeTo(int value, int flags) {
+        if (mVolumeType == MediaSession.VOLUME_TYPE_LOCAL) {
+            mAudioManager.setStreamVolume(mAudioStream, value, flags);
+        } else {
+            if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
+                // Nothing to do. The volume can't be set directly.
+                return;
+            }
+            mSessionCb.setVolumeTo(value);
         }
-        mSessionCb.setVolumeTo(value);
     }
 
     /**
@@ -352,7 +384,7 @@
      * @return The current type of playback.
      */
     public int getPlaybackType() {
-        return mPlaybackType;
+        return mVolumeType;
     }
 
     /**
@@ -683,6 +715,11 @@
         }
 
         @Override
+        public void setMediaButtonReceiver(ComponentName mbr) {
+            mMediaButtonReceiver = mbr;
+        }
+
+        @Override
         public void setMetadata(MediaMetadata metadata) {
             mMetadata = metadata;
             mHandler.post(MessageHandler.MSG_UPDATE_METADATA);
@@ -754,7 +791,7 @@
         public void configureVolumeHandling(int type, int arg1, int arg2) throws RemoteException {
             switch(type) {
                 case MediaSession.VOLUME_TYPE_LOCAL:
-                    mPlaybackType = type;
+                    mVolumeType = type;
                     int audioStream = arg1;
                     if (isValidStream(audioStream)) {
                         mAudioStream = audioStream;
@@ -764,7 +801,7 @@
                     }
                     break;
                 case MediaSession.VOLUME_TYPE_REMOTE:
-                    mPlaybackType = type;
+                    mVolumeType = type;
                     mVolumeControlType = arg1;
                     mMaxVolume = arg2;
                     break;
@@ -985,6 +1022,35 @@
         }
 
         @Override
+        public ParcelableVolumeInfo getVolumeAttributes() {
+            synchronized (mLock) {
+                int type;
+                int max;
+                int current;
+                if (mVolumeType == MediaSession.VOLUME_TYPE_REMOTE) {
+                    type = mVolumeControlType;
+                    max = mMaxVolume;
+                    current = mCurrentVolume;
+                } else {
+                    type = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
+                    max = mAudioManager.getStreamMaxVolume(mAudioStream);
+                    current = mAudioManager.getStreamVolume(mAudioStream);
+                }
+                return new ParcelableVolumeInfo(mVolumeType, mAudioStream, type, max, current);
+            }
+        }
+
+        @Override
+        public void adjustVolumeBy(int delta, int flags) {
+            MediaSessionRecord.this.adjustVolumeBy(delta, flags);
+        }
+
+        @Override
+        public void setVolumeTo(int value, int flags) {
+            MediaSessionRecord.this.setVolumeTo(value, flags);
+        }
+
+        @Override
         public void play() throws RemoteException {
             mSessionCb.play();
         }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 67065ba..685717f 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -23,6 +23,7 @@
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -88,6 +89,7 @@
 
     private KeyguardManager mKeyguardManager;
     private IAudioService mAudioService;
+    private ContentResolver mContentResolver;
 
     private MediaSessionRecord mPrioritySession;
     private int mCurrentUserId = -1;
@@ -115,6 +117,7 @@
         mKeyguardManager =
                 (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
         mAudioService = getAudioService();
+        mContentResolver = getContext().getContentResolver();
     }
 
     private IAudioService getAudioService() {
@@ -381,8 +384,7 @@
             return false;
         }
         if (compName != null) {
-            final String enabledNotifListeners = Settings.Secure.getStringForUser(
-                    getContext().getContentResolver(),
+            final String enabledNotifListeners = Settings.Secure.getStringForUser(mContentResolver,
                     Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
                     userId);
             if (enabledNotifListeners != null) {
@@ -485,6 +487,9 @@
         synchronized (mLock) {
             List<MediaSessionRecord> records = mPriorityStack.getActiveSessions(userId);
             int size = records.size();
+            if (size > 0) {
+                persistMediaButtonReceiverLocked(records.get(0));
+            }
             ArrayList<MediaSessionToken> tokens = new ArrayList<MediaSessionToken>();
             for (int i = 0; i < size; i++) {
                 tokens.add(new MediaSessionToken(records.get(i).getControllerBinder()));
@@ -504,6 +509,16 @@
         }
     }
 
+    private void persistMediaButtonReceiverLocked(MediaSessionRecord record) {
+        ComponentName receiver = record.getMediaButtonReceiver();
+        if (receiver != null) {
+            Settings.System.putStringForUser(mContentResolver,
+                    Settings.System.MEDIA_BUTTON_RECEIVER,
+                    receiver == null ? "" : receiver.flattenToString(),
+                    UserHandle.USER_CURRENT);
+        }
+    }
+
     private MediaRouteProviderProxy.RoutesListener mRoutesCallback
             = new MediaRouteProviderProxy.RoutesListener() {
         @Override
@@ -881,14 +896,6 @@
 
         private void dispatchAdjustVolumeByLocked(int suggestedStream, int delta, int flags,
                 MediaSessionRecord session) {
-            int direction = 0;
-            int steps = delta;
-            if (delta > 0) {
-                direction = 1;
-            } else if (delta < 0) {
-                direction = -1;
-                steps = -delta;
-            }
             if (DEBUG) {
                 String sessionInfo = session == null ? null : session.getSessionInfo().toString();
                 Log.d(TAG, "Adjusting session " + sessionInfo + " by " + delta + ". flags=" + flags
@@ -901,6 +908,14 @@
                         mAudioService.adjustSuggestedStreamVolume(delta, suggestedStream, flags,
                                 getContext().getOpPackageName());
                     } else {
+                        int direction = 0;
+                        int steps = delta;
+                        if (delta > 0) {
+                            direction = 1;
+                        } else if (delta < 0) {
+                            direction = -1;
+                            steps = -delta;
+                        }
                         for (int i = 0; i < steps; i++) {
                             mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
                                     flags, getContext().getOpPackageName());
@@ -910,26 +925,7 @@
                     Log.e(TAG, "Error adjusting default volume.", e);
                 }
             } else {
-                if (session.getPlaybackType() == MediaSession.VOLUME_TYPE_LOCAL) {
-                    try {
-                        if (delta == 0) {
-                            mAudioService.adjustSuggestedStreamVolume(delta,
-                                    session.getAudioStream(), flags,
-                                    getContext().getOpPackageName());
-                        } else {
-                            for (int i = 0; i < steps; i++) {
-                                mAudioService.adjustSuggestedStreamVolume(direction,
-                                        session.getAudioStream(), flags,
-                                        getContext().getOpPackageName());
-                            }
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error adjusting volume for stream "
-                                + session.getAudioStream(), e);
-                    }
-                } else if (session.getPlaybackType() == MediaSession.VOLUME_TYPE_REMOTE) {
-                    session.adjustVolumeBy(delta);
-                }
+                session.adjustVolumeBy(delta, flags);
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 2a7b4f6..1d53016 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -34,9 +34,9 @@
 public class BackgroundDexOptService extends JobService {
     static final String TAG = "BackgroundDexOptService";
 
-    static final int BACKGROUND_DEXOPT_JOB = 808;
+    static final int BACKGROUND_DEXOPT_JOB = 800;
     private static ComponentName sDexoptServiceName = new ComponentName(
-            BackgroundDexOptService.class.getPackage().getName(),
+            "android",
             BackgroundDexOptService.class.getName());
 
     final AtomicBoolean mIdleTime = new AtomicBoolean(false);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 90e263a..bf04235 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -53,7 +53,6 @@
 import com.android.server.Watchdog;
 import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.storage.DeviceStorageMonitorInternal;
-import com.android.server.storage.DeviceStorageMonitorInternal;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -91,7 +90,6 @@
 import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
-import android.content.pm.PackageInstallerParams;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageParser.PackageParserException;
@@ -623,10 +621,10 @@
         private final AtomicLong mLastWritten = new AtomicLong(0);
         private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
 
-        private boolean mIsFirstBoot = false;
+        private boolean mIsHistoricalPackageUsageAvailable = true;
 
-        boolean isFirstBoot() {
-            return mIsFirstBoot;
+        boolean isHistoricalPackageUsageAvailable() {
+            return mIsHistoricalPackageUsageAvailable;
         }
 
         void write(boolean force) {
@@ -717,7 +715,7 @@
                         pkg.mLastPackageUsageTimeInMills = timeInMillis;
                     }
                 } catch (FileNotFoundException expected) {
-                    mIsFirstBoot = true;
+                    mIsHistoricalPackageUsageAvailable = false;
                 } catch (IOException e) {
                     Log.w(TAG, "Failed to read package usage times", e);
                 } finally {
@@ -1744,7 +1742,7 @@
 
     @Override
     public boolean isFirstBoot() {
-        return !mRestoredSettings || mPackageUsage.isFirstBoot();
+        return !mRestoredSettings;
     }
 
     @Override
@@ -3363,6 +3361,26 @@
                 if (matches.get(i).getTargetUserId() == targetUserId) return true;
             }
         }
+
+        ArrayList<String> packageNames = null;
+        SparseArray<ArrayList<String>> fromSource =
+                mSettings.mCrossProfilePackageInfo.get(sourceUserId);
+        if (fromSource != null) {
+            packageNames = fromSource.get(targetUserId);
+        }
+        if (packageNames.contains(intent.getPackage())) {
+            return true;
+        }
+        // We need the package name, so we try to resolve with the loosest flags possible
+        List<ResolveInfo> resolveInfos = mActivities.queryIntent(
+                intent, resolvedType, PackageManager.GET_UNINSTALLED_PACKAGES, targetUserId);
+        int count = resolveInfos.size();
+        for (int i = 0; i < count; i++) {
+            ResolveInfo resolveInfo = resolveInfos.get(i);
+            if (packageNames.contains(resolveInfo.activityInfo.packageName)) {
+                return true;
+            }
+        }
         return false;
     }
 
@@ -3403,6 +3421,14 @@
         synchronized (mPackages) {
             final String pkgName = intent.getPackage();
             if (pkgName == null) {
+                //Check if the intent needs to be forwarded to another user for this package
+                ArrayList<ResolveInfo> crossProfileResult =
+                        queryIntentActivitiesCrossProfilePackage(
+                                intent, resolvedType, flags, userId);
+                if (!crossProfileResult.isEmpty()) {
+                    // Skip the current profile
+                    return crossProfileResult;
+                }
                 List<ResolveInfo> result;
                 List<CrossProfileIntentFilter> matchingFilters =
                         getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
@@ -3426,6 +3452,13 @@
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
+                ArrayList<ResolveInfo> crossProfileResult =
+                        queryIntentActivitiesCrossProfilePackage(
+                                intent, resolvedType, flags, userId, pkg, pkgName);
+                if (!crossProfileResult.isEmpty()) {
+                    // Skip the current profile
+                    return crossProfileResult;
+                }
                 return mActivities.queryIntentForPackage(intent, resolvedType, flags,
                         pkg.activities, userId);
             }
@@ -3446,7 +3479,8 @@
                     ResolveInfo resolveInfo = checkTargetCanHandle(filter, intent, resolvedType,
                             flags, sourceUserId);
                     if (resolveInfo != null) {
-                        return createForwardingResolveInfo(filter, sourceUserId);
+                        return createForwardingResolveInfo(
+                                filter, sourceUserId, filter.getTargetUserId());
                     }
                 }
             }
@@ -3454,6 +3488,56 @@
         return null;
     }
 
+    private ArrayList<ResolveInfo> queryIntentActivitiesCrossProfilePackage(
+            Intent intent, String resolvedType, int flags, int userId) {
+        ArrayList<ResolveInfo> matchingResolveInfos = new ArrayList<ResolveInfo>();
+        SparseArray<ArrayList<String>> sourceForwardingInfo =
+                mSettings.mCrossProfilePackageInfo.get(userId);
+        if (sourceForwardingInfo != null) {
+            int NI = sourceForwardingInfo.size();
+            for (int i = 0; i < NI; i++) {
+                int targetUserId = sourceForwardingInfo.keyAt(i);
+                ArrayList<String> packageNames = sourceForwardingInfo.valueAt(i);
+                List<ResolveInfo> resolveInfos = mActivities.queryIntent(
+                        intent, resolvedType, flags, targetUserId);
+                int NJ = resolveInfos.size();
+                for (int j = 0; j < NJ; j++) {
+                    ResolveInfo resolveInfo = resolveInfos.get(j);
+                    if (packageNames.contains(resolveInfo.activityInfo.packageName)) {
+                        matchingResolveInfos.add(createForwardingResolveInfo(
+                                resolveInfo.filter, userId, targetUserId));
+                    }
+                }
+            }
+        }
+        return matchingResolveInfos;
+    }
+
+    private ArrayList<ResolveInfo> queryIntentActivitiesCrossProfilePackage(
+            Intent intent, String resolvedType, int flags, int userId, PackageParser.Package pkg,
+            String packageName) {
+        ArrayList<ResolveInfo> matchingResolveInfos = new ArrayList<ResolveInfo>();
+        SparseArray<ArrayList<String>> sourceForwardingInfo =
+                mSettings.mCrossProfilePackageInfo.get(userId);
+        if (sourceForwardingInfo != null) {
+            int NI = sourceForwardingInfo.size();
+            for (int i = 0; i < NI; i++) {
+                int targetUserId = sourceForwardingInfo.keyAt(i);
+                if (sourceForwardingInfo.valueAt(i).contains(packageName)) {
+                    List<ResolveInfo> resolveInfos = mActivities.queryIntentForPackage(
+                            intent, resolvedType, flags, pkg.activities, targetUserId);
+                    int NJ = resolveInfos.size();
+                    for (int j = 0; j < NJ; j++) {
+                        ResolveInfo resolveInfo = resolveInfos.get(j);
+                        matchingResolveInfos.add(createForwardingResolveInfo(
+                                resolveInfo.filter, userId, targetUserId));
+                    }
+                }
+            }
+        }
+        return matchingResolveInfos;
+    }
+
     // Return matching ResolveInfo if any for skip current profile intent filters.
     private ResolveInfo queryCrossProfileIntents(
             List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
@@ -3486,17 +3570,18 @@
         List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent,
                 resolvedType, flags, filter.getTargetUserId());
         if (resultTargetUser != null) {
-            return createForwardingResolveInfo(filter, sourceUserId);
+            return createForwardingResolveInfo(filter, sourceUserId, filter.getTargetUserId());
         }
         return null;
     }
 
-    private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter,
-            int sourceUserId) {
+    private ResolveInfo createForwardingResolveInfo(IntentFilter filter,
+            int sourceUserId, int targetUserId) {
+        ResolveInfo forwardingResolveInfo = new ResolveInfo();
         String className;
-        int targetUserId = filter.getTargetUserId();
         if (targetUserId == UserHandle.USER_OWNER) {
             className = FORWARD_INTENT_TO_USER_OWNER;
+            forwardingResolveInfo.showTargetUserIcon = true;
         } else {
             className = FORWARD_INTENT_TO_MANAGED_PROFILE;
         }
@@ -3504,13 +3589,13 @@
                 mAndroidApplication.packageName, className);
         ActivityInfo forwardingActivityInfo = getActivityInfo(forwardingActivityComponentName, 0,
                 sourceUserId);
-        ResolveInfo forwardingResolveInfo = new ResolveInfo();
         forwardingResolveInfo.activityInfo = forwardingActivityInfo;
         forwardingResolveInfo.priority = 0;
         forwardingResolveInfo.preferredOrder = 0;
         forwardingResolveInfo.match = 0;
         forwardingResolveInfo.isDefault = true;
         forwardingResolveInfo.filter = filter;
+        forwardingResolveInfo.targetUserId = targetUserId;
         return forwardingResolveInfo;
     }
 
@@ -4539,7 +4624,7 @@
             // The exception is first boot of a non-eng device, which
             // should do a full dexopt.
             boolean eng = "eng".equals(SystemProperties.get("ro.build.type"));
-            if (eng || !isFirstBoot()) {
+            if (eng || (!isFirstBoot() && mPackageUsage.isHistoricalPackageUsageAvailable())) {
                 // TODO: add a property to control this?
                 long dexOptLRUThresholdInMinutes;
                 if (eng) {
@@ -11604,6 +11689,22 @@
         }
     }
 
+    public void addCrossProfileIntentsForPackage(String packageName,
+            int sourceUserId, int targetUserId) {
+        mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        mSettings.addCrossProfilePackage(packageName, sourceUserId, targetUserId);
+        mSettings.writePackageRestrictionsLPr(sourceUserId);
+    }
+
+    public void removeCrossProfileIntentsForPackage(String packageName,
+            int sourceUserId, int targetUserId) {
+        mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        mSettings.removeCrossProfilePackage(packageName, sourceUserId, targetUserId);
+        mSettings.writePackageRestrictionsLPr(sourceUserId);
+    }
+
     @Override
     public void clearCrossProfileIntentFilters(int sourceUserId) {
         mContext.enforceCallingOrSelfPermission(
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 3483fae..1867ff3 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -31,12 +31,14 @@
 import android.net.Uri;
 import android.os.PatternMatcher;
 import android.util.LogPrinter;
+
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.XmlUtils;
 import com.android.server.pm.PackageManagerService.DumpState;
 
 import java.util.Collection;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -134,6 +136,10 @@
             "persistent-preferred-activities";
     static final String TAG_CROSS_PROFILE_INTENT_FILTERS =
             "crossProfile-intent-filters";
+    private static final String TAG_CROSS_PROFILE_PACKAGE_INFO = "cross-profile-package-info";
+    private static final String CROSS_PROFILE_PACKAGE_INFO_ATTR_TARGET_USER_ID = "target-user-id";
+    private static final String CROSS_PROFILE_PACKAGE_INFO_TAG_PACKAGE_NAME = "package-name";
+    private static final String CROSS_PROFILE_PACKAGE_INFO_ATTR_PACKAGE_NAME = "value";
     //Old name. Kept for compatibility
     static final String TAG_FORWARDING_INTENT_FILTERS =
             "forwarding-intent-filters";
@@ -240,6 +246,11 @@
 
     public final KeySetManager mKeySetManager = new KeySetManager(mPackages);
 
+    // A mapping of (sourceUserId, targetUserId, packageNames) for forwarding the intents of a
+    // package.
+    final SparseArray<SparseArray<ArrayList<String>>>
+            mCrossProfilePackageInfo = new SparseArray<SparseArray<ArrayList<String>>>();
+
     Settings(Context context) {
         this(context, Environment.getDataDirectory());
     }
@@ -262,6 +273,47 @@
         mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
     }
 
+    public void addCrossProfilePackage(
+            String packageName, int sourceUserId, int targetUserId) {
+        synchronized(mCrossProfilePackageInfo) {
+            SparseArray<ArrayList<String>> sourceForwardingInfo =
+                    mCrossProfilePackageInfo.get(sourceUserId);
+            if (sourceForwardingInfo == null) {
+                sourceForwardingInfo = new SparseArray<ArrayList<String>>();
+                mCrossProfilePackageInfo.put(sourceUserId, sourceForwardingInfo);
+            }
+            ArrayList<String> packageNames = sourceForwardingInfo.get(targetUserId);
+            if (packageNames == null) {
+                packageNames = new ArrayList<String>();
+                sourceForwardingInfo.put(targetUserId, packageNames);
+            }
+            if (!packageNames.contains(packageName)) {
+                packageNames.add(packageName);
+            }
+        }
+    }
+
+    public void removeCrossProfilePackage(
+            String packageName, int sourceUserId, int targetUserId) {
+        synchronized(mCrossProfilePackageInfo) {
+            SparseArray<ArrayList<String>> sourceForwardingInfo =
+                    mCrossProfilePackageInfo.get(sourceUserId);
+            if (sourceForwardingInfo == null) {
+                return;
+            }
+            ArrayList<String> packageNames = sourceForwardingInfo.get(targetUserId);
+            if (packageNames != null && packageNames.contains(packageName)) {
+                packageNames.remove(packageName);
+                if (packageNames.isEmpty()) {
+                    sourceForwardingInfo.remove(targetUserId);
+                    if (sourceForwardingInfo.size() == 0) {
+                        mCrossProfilePackageInfo.remove(sourceUserId);
+                    }
+                }
+            }
+        }
+    }
+
     PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
             String nativeLibraryPathString, String cpuAbiString, int pkgFlags, UserHandle user, boolean add) {
@@ -1005,6 +1057,68 @@
         }
     }
 
+    private void readCrossProfilePackageInfoLPw(XmlPullParser parser, int userId)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            String tagName = parser.getName();
+            if (tagName.equals(TAG_ITEM)) {
+                String targetUserIdString = parser.getAttributeValue(null,
+                        CROSS_PROFILE_PACKAGE_INFO_ATTR_TARGET_USER_ID);
+                if (targetUserIdString == null) {
+                    String msg = "Missing element under " + TAG +": "
+                            + CROSS_PROFILE_PACKAGE_INFO_ATTR_TARGET_USER_ID + " at " +
+                            parser.getPositionDescription();
+                    PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                    continue;
+                }
+                int targetUserId = Integer.parseInt(targetUserIdString);
+                readCrossProfilePackageInfoForTargetLPw(parser, userId, targetUserId);
+            } else {
+                String msg = "Unknown element under " +  TAG_CROSS_PROFILE_PACKAGE_INFO + ": " +
+                        parser.getName();
+                PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+    }
+
+    private void readCrossProfilePackageInfoForTargetLPw(
+            XmlPullParser parser, int sourceUserId, int targetUserId)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            String tagName = parser.getName();
+            if (tagName.equals(CROSS_PROFILE_PACKAGE_INFO_TAG_PACKAGE_NAME)) {
+                String packageName = parser.getAttributeValue(
+                        null, CROSS_PROFILE_PACKAGE_INFO_ATTR_PACKAGE_NAME);
+                if (packageName == null) {
+                    String msg = "Missing element under " + TAG +": "
+                            + CROSS_PROFILE_PACKAGE_INFO_TAG_PACKAGE_NAME + " at " +
+                            parser.getPositionDescription();
+                    PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                    continue;
+                }
+                addCrossProfilePackage(packageName, sourceUserId, targetUserId);
+            } else {
+                String msg = "Unknown element under " +  TAG_ITEM + ": " +
+                        parser.getName();
+                PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+    }
+
     void readPackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -1136,6 +1250,8 @@
                 } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)
                         || tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
                     readCrossProfileIntentFiltersLPw(parser, userId);
+                } else if (tagName.equals(TAG_CROSS_PROFILE_PACKAGE_INFO)){
+                    readCrossProfilePackageInfoLPw(parser, userId);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
                           + parser.getName());
@@ -1227,6 +1343,32 @@
         serializer.endTag(null, TAG_CROSS_PROFILE_INTENT_FILTERS);
     }
 
+    void writeCrossProfilePackageInfoLPr(XmlSerializer serializer, int userId)
+            throws IllegalArgumentException, IllegalStateException, IOException {
+        SparseArray<ArrayList<String>> sourceForwardingInfo = mCrossProfilePackageInfo.get(userId);
+        if (sourceForwardingInfo == null) {
+            return;
+        }
+        serializer.startTag(null, TAG_CROSS_PROFILE_PACKAGE_INFO);
+        int NI = sourceForwardingInfo.size();
+        for (int i = 0; i < NI; i++) {
+            int targetUserId = sourceForwardingInfo.keyAt(i);
+            ArrayList<String> packageNames = sourceForwardingInfo.valueAt(i);
+            serializer.startTag(null, TAG_ITEM);
+            serializer.attribute(null, CROSS_PROFILE_PACKAGE_INFO_ATTR_TARGET_USER_ID,
+                    Integer.toString(targetUserId));
+            int NJ = packageNames.size();
+            for (int j = 0; j < NJ; j++) {
+                serializer.startTag(null, CROSS_PROFILE_PACKAGE_INFO_TAG_PACKAGE_NAME);
+                serializer.attribute(null, CROSS_PROFILE_PACKAGE_INFO_ATTR_PACKAGE_NAME,
+                        packageNames.get(j));
+                serializer.endTag(null, CROSS_PROFILE_PACKAGE_INFO_TAG_PACKAGE_NAME);
+            }
+            serializer.endTag(null, TAG_ITEM);
+        }
+        serializer.endTag(null, TAG_CROSS_PROFILE_PACKAGE_INFO);
+    }
+
     void writePackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1327,6 +1469,8 @@
 
             writeCrossProfileIntentFiltersLPr(serializer, userId);
 
+            writeCrossProfilePackageInfoLPr(serializer, userId);
+
             serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
 
             serializer.endDocument();
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1839259..a0cb098 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -412,13 +412,17 @@
 
     @Override
     public Bitmap getUserIcon(int userId) {
-        checkManageUsersPermission("read users");
         synchronized (mPackagesLock) {
             UserInfo info = mUsers.get(userId);
             if (info == null || info.partial) {
                 Slog.w(LOG_TAG, "getUserIcon: unknown user #" + userId);
                 return null;
             }
+            int callingGroupId = mUsers.get(UserHandle.getCallingUserId()).profileGroupId;
+            if (callingGroupId == UserInfo.NO_PROFILE_GROUP_ID
+                    || callingGroupId != info.profileGroupId) {
+                checkManageUsersPermission("get the icon of a user who is not related");
+            }
             if (info.iconPath == null) {
                 return null;
             }
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index b9ef492..32546df 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -186,16 +186,12 @@
                 if (resolveInfo.serviceInfo == null) continue;
 
                 String packageName = resolveInfo.serviceInfo.packageName;
-                // STOPSHIP Reenable this check once the GMS Core prebuild library has the
-                // permission.
-                /*
                 if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
                         != PackageManager.PERMISSION_GRANTED) {
                     Log.w(TAG, "Skipping agent because package " + packageName
                             + " does not have permission " + PERMISSION_PROVIDE_AGENT + ".");
                     continue;
                 }
-                */
 
                 ComponentName name = getComponentName(resolveInfo);
                 if (!enabledAgents.contains(name)) continue;
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index 1535e7a..23c0a4c 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -20,12 +20,19 @@
 import android.media.tv.TvStreamConfig;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Message;
 import android.view.Surface;
+import android.util.Slog;
+
+import java.util.LinkedList;
+import java.util.Queue;
 
 /**
  * Provides access to the low-level TV input hardware abstraction layer.
  */
-final class TvInputHal {
+final class TvInputHal implements Handler.Callback {
+    private final static String TAG = TvInputHal.class.getSimpleName();
+
     public final static int SUCCESS = 0;
     public final static int ERROR_NO_INIT = -1;
     public final static int ERROR_STALE_CONFIG = -2;
@@ -35,6 +42,12 @@
     public static final int TYPE_BUILT_IN_TUNER = 2;
     public static final int TYPE_PASSTHROUGH = 3;
 
+    public static final int EVENT_OPEN = 0;
+    // Below should be in sync with hardware/libhardware/include/hardware/tv_input.h
+    public static final int EVENT_DEVICE_AVAILABLE = 1;
+    public static final int EVENT_DEVICE_UNAVAILABLE = 2;
+    public static final int EVENT_STREAM_CONFIGURATION_CHANGED = 3;
+
     public interface Callback {
         public void onDeviceAvailable(
                 TvInputHardwareInfo info, TvStreamConfig[] configs);
@@ -50,7 +63,7 @@
             int generation);
     private static native void nativeClose(long ptr);
 
-    private long mPtr = 0l;
+    private volatile long mPtr = 0;
     private final Callback mCallback;
     private final HandlerThread mThread = new HandlerThread("TV input HAL event thread");
     private final Handler mHandler;
@@ -60,21 +73,23 @@
     public TvInputHal(Callback callback) {
         mCallback = callback;
         mThread.start();
-        mHandler = new Handler(mThread.getLooper());
+        mHandler = new Handler(mThread.getLooper(), this);
     }
 
     public void init() {
         mPtr = nativeOpen();
+        mHandler.sendEmptyMessage(EVENT_OPEN);
     }
 
     public int setSurface(int deviceId, Surface surface, TvStreamConfig streamConfig) {
-        if (mPtr == 0) {
+        long ptr = mPtr;
+        if (ptr == 0) {
             return ERROR_NO_INIT;
         }
         if (mStreamConfigGeneration != streamConfig.getGeneration()) {
             return ERROR_STALE_CONFIG;
         }
-        if (nativeSetSurface(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) {
+        if (nativeSetSurface(ptr, deviceId, streamConfig.getStreamId(), surface) == 0) {
             return SUCCESS;
         } else {
             return ERROR_UNKNOWN;
@@ -82,44 +97,81 @@
     }
 
     public void close() {
-        if (mPtr != 0l) {
-            nativeClose(mPtr);
+        long ptr = mPtr;
+        if (ptr != 0l) {
+            nativeClose(ptr);
             mThread.quitSafely();
         }
     }
 
-    private synchronized void retrieveStreamConfigs(int deviceId) {
+    private synchronized void retrieveStreamConfigs(long ptr, int deviceId) {
         ++mStreamConfigGeneration;
-        mStreamConfigs = nativeGetStreamConfigs(mPtr, deviceId, mStreamConfigGeneration);
+        mStreamConfigs = nativeGetStreamConfigs(ptr, deviceId, mStreamConfigGeneration);
     }
 
     // Called from native
-    private void deviceAvailableFromNative(final TvInputHardwareInfo info) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                retrieveStreamConfigs(info.getDeviceId());
+    private void deviceAvailableFromNative(TvInputHardwareInfo info) {
+        mHandler.sendMessage(
+                mHandler.obtainMessage(EVENT_DEVICE_AVAILABLE, info));
+    }
+
+    private void deviceUnavailableFromNative(int deviceId) {
+        mHandler.sendMessage(
+                mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0));
+    }
+
+    private void streamConfigsChangedFromNative(int deviceId) {
+        mHandler.sendMessage(
+                mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0));
+    }
+
+    // Handler.Callback implementation
+
+    private Queue<Message> mPendingMessageQueue = new LinkedList<Message>();
+
+    @Override
+    public boolean handleMessage(Message msg) {
+        long ptr = mPtr;
+        if (ptr == 0) {
+            mPendingMessageQueue.add(msg);
+            return true;
+        }
+        while (!mPendingMessageQueue.isEmpty()) {
+            handleMessageInternal(ptr, mPendingMessageQueue.remove());
+        }
+        handleMessageInternal(ptr, msg);
+        return true;
+    }
+
+    private void handleMessageInternal(long ptr, Message msg) {
+        switch (msg.what) {
+            case EVENT_OPEN:
+                // No-op
+                break;
+
+            case EVENT_DEVICE_AVAILABLE: {
+                TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj;
+                retrieveStreamConfigs(ptr, info.getDeviceId());
                 mCallback.onDeviceAvailable(info, mStreamConfigs);
+                break;
             }
-        });
-    }
 
-    private void deviceUnavailableFromNative(final int deviceId) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
+            case EVENT_DEVICE_UNAVAILABLE: {
+                int deviceId = msg.arg1;
                 mCallback.onDeviceUnavailable(deviceId);
+                break;
             }
-        });
-    }
 
-    private void streamConfigsChangedFromNative(final int deviceId) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                retrieveStreamConfigs(deviceId);
+            case EVENT_STREAM_CONFIGURATION_CHANGED: {
+                int deviceId = msg.arg1;
+                retrieveStreamConfigs(ptr, deviceId);
                 mCallback.onStreamConfigurationChanged(deviceId, mStreamConfigs);
+                break;
             }
-        });
+
+            default:
+                Slog.e(TAG, "Unknown event: " + msg);
+                break;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 99b5b03..6798f3f 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -106,11 +106,9 @@
         mLogHandler = new LogHandler(IoThread.get().getLooper());
 
         mTvInputHardwareManager = new TvInputHardwareManager(context);
-        registerBroadcastReceivers();
 
         synchronized (mLock) {
             mUserStates.put(mCurrentUserId, new UserState());
-            buildTvInputListLocked(mCurrentUserId);
         }
     }
 
@@ -119,6 +117,16 @@
         publishBinderService(Context.TV_INPUT_SERVICE, new BinderService());
     }
 
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            registerBroadcastReceivers();
+            synchronized (mLock) {
+                buildTvInputListLocked(mCurrentUserId);
+            }
+        }
+    }
+
     private void registerBroadcastReceivers() {
         PackageMonitor monitor = new PackageMonitor() {
             @Override
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 9a5079d..3696e24 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -61,8 +61,7 @@
         jobject canvas, jint width, jint height) {
 
     SkBitmap* bitmap = new SkBitmap;
-    bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
-    bitmap->allocPixels();
+    bitmap->allocN32Pixels(width, height);
     bitmap->eraseColor(0);
     INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(bitmap));
 
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 9cecdf0..7b8e6fd 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -75,7 +75,6 @@
     static JTvInputHal* createInstance(JNIEnv* env, jobject thiz);
 
     int setSurface(int deviceId, int streamId, const sp<Surface>& surface);
-    void getStreamConfigs(int deviceId, jobjectArray* array);
     const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
 
 private:
diff --git a/telecomm/java/android/telecomm/PhoneApplication.java b/telecomm/java/android/telecomm/PhoneApplication.java
deleted file mode 100644
index 1da54e0..0000000
--- a/telecomm/java/android/telecomm/PhoneApplication.java
+++ /dev/null
@@ -1,183 +0,0 @@
-package android.telecomm;
-
-import android.annotation.SystemApi;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.telecomm.ITelecommService;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Class for managing the primary phone application that will receive incoming calls, and be allowed
- * to make emergency outgoing calls.
- *
- * @hide
- */
-public class PhoneApplication {
-    private static final String TAG = PhoneApplication.class.getSimpleName();
-    private static final String TELECOMM_SERVICE_NAME = "telecomm";
-
-    /**
-     * Sets the specified package name as the default phone application. The caller of this method
-     * needs to have permission to write to secure settings.
-     *
-     * @hide
-     * */
-    @SystemApi
-    public static void setDefaultPhoneApplication(String packageName, Context context) {
-        // Get old package name
-        String oldPackageName = Settings.Secure.getString(context.getContentResolver(),
-                Settings.Secure.PHONE_DEFAULT_APPLICATION);
-
-        if (packageName != null && oldPackageName != null && packageName.equals(oldPackageName)) {
-            // No change
-            return;
-        }
-
-        // Only make the change if the new package belongs to a valid phone application
-        List<ComponentName> componentNames = getInstalledPhoneApplications(context);
-        ComponentName foundComponent = null;
-        for (ComponentName componentName : componentNames) {
-            if (TextUtils.equals(componentName.getPackageName(), packageName)) {
-                foundComponent = componentName;
-                break;
-            }
-        }
-
-        if (foundComponent != null) {
-            // Update the secure setting.
-            Settings.Secure.putString(context.getContentResolver(),
-                    Settings.Secure.PHONE_DEFAULT_APPLICATION, foundComponent.getPackageName());
-        }
-    }
-
-    /**
-     * Returns the installed phone application that will be used to receive incoming calls, and is
-     * allowed to make emergency calls.
-     *
-     * The application will be returned in order of preference:
-     * 1) User selected phone application (if still installed)
-     * 2) Pre-installed system dialer (if not disabled)
-     * 3) Null
-     *
-     * @hide
-     * */
-    @SystemApi
-    public static ComponentName getDefaultPhoneApplication(Context context) {
-        String defaultPackageName = Settings.Secure.getString(context.getContentResolver(),
-                Settings.Secure.PHONE_DEFAULT_APPLICATION);
-
-        final List<ComponentName> componentNames = getInstalledPhoneApplications(context);
-        if (!TextUtils.isEmpty(defaultPackageName)) {
-            for (ComponentName componentName : componentNames) {
-                if (TextUtils.equals(componentName.getPackageName(), defaultPackageName)) {
-                    return componentName;
-                }
-            }
-        }
-
-        // No user-set dialer found, fallback to system dialer
-        ComponentName systemDialer = null;
-        try {
-            systemDialer = getTelecommService().getSystemPhoneApplication();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelecommService#getSystemPhoneApplication", e);
-            return null;
-        }
-
-        if (systemDialer == null) {
-            // No system dialer configured at build time
-            return null;
-        }
-
-        // Verify that the system dialer has not been disabled.
-        return getComponentName(componentNames, systemDialer.getPackageName());
-    }
-
-    /**
-     * Returns a list of installed and available phone applications.
-     *
-     * In order to appear in the list, a phone application must implement an intent-filter with
-     * the DIAL intent for the following schemes:
-     *
-     * 1) Empty scheme
-     * 2) tel Uri scheme
-     *
-     * @hide
-     **/
-    @SystemApi
-    public static List<ComponentName> getInstalledPhoneApplications(Context context) {
-        PackageManager packageManager = context.getPackageManager();
-
-        // Get the list of apps registered for the DIAL intent with empty scheme
-        Intent intent = new Intent(Intent.ACTION_DIAL);
-        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
-
-        List<ComponentName> componentNames = new ArrayList<ComponentName> ();
-
-        for (ResolveInfo resolveInfo : resolveInfoList) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            if (activityInfo == null) {
-                continue;
-            }
-            final ComponentName componentName =
-                    new ComponentName(activityInfo.packageName, activityInfo.name);
-            componentNames.add(componentName);
-        }
-
-        // TODO: Filter for apps that don't handle DIAL intent with tel scheme
-        return componentNames;
-    }
-
-    /**
-     * Returns the {@link ComponentName} for the installed phone application for a given package
-     * name.
-     *
-     * @param context A valid context.
-     * @param packageName to retrieve the {@link ComponentName} for.
-     *
-     * @return The {@link ComponentName} for the installed phone application corresponding to the
-     * package name, or null if none is found.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static ComponentName getPhoneApplicationForPackageName(Context context,
-            String packageName) {
-        return getComponentName(getInstalledPhoneApplications(context), packageName);
-    }
-
-    /**
-     * Returns the component from a list of application components that corresponds to the package
-     * name.
-     *
-     * @param componentNames A list of component names
-     * @param packageName The package name to look for
-     * @return The {@link ComponentName} that matches the provided packageName, or null if not
-     *         found.
-     */
-    private static ComponentName getComponentName(List<ComponentName> componentNames,
-            String packageName) {
-        for (ComponentName componentName : componentNames) {
-            if (TextUtils.equals(packageName, componentName.getPackageName())) {
-                return componentName;
-            }
-        }
-        return null;
-    }
-
-    private static ITelecommService getTelecommService() {
-        return ITelecommService.Stub.asInterface(ServiceManager.getService(TELECOMM_SERVICE_NAME));
-    }
-}
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
index 0952097..0a12c08 100644
--- a/telecomm/java/android/telecomm/TelecommConstants.java
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -56,21 +56,6 @@
     public static final String ACTION_CALL_SERVICE_SELECTOR = CallServiceSelector.class.getName();
 
     /**
-     * Activity action: Ask the user to change the default phone application. This will show a
-     * dialog that asks the user whether they want to replace the current default phone application
-     * with the one defined in {@link #EXTRA_PACKAGE_NAME}.
-     */
-    public static final String ACTION_CHANGE_DEFAULT_PHONE =
-            "android.telecomm.ACTION_CHANGE_DEFAULT_PHONE";
-
-    /**
-     * The PackageName string passed in as an extra for {@link #ACTION_CHANGE_DEFAULT_PHONE}.
-     *
-     * @see #ACTION_CHANGE_DEFAULT_PHONE
-     */
-    public static final String EXTRA_PACKAGE_NAME = "package";
-
-    /**
      * Optional extra for {@link Intent#ACTION_CALL} containing a boolean that determines whether
      * the speakerphone should be automatically turned on for an outgoing call.
      */
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index 989c2cd..a97e7e4 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -16,9 +16,7 @@
 
 package android.telecomm;
 
-import android.content.ComponentName;
 import android.content.Context;
-import android.os.RemoteException;
 
 import com.android.internal.telecomm.ITelecommService;
 
@@ -47,14 +45,4 @@
     public static TelecommManager from(Context context) {
         return (TelecommManager) context.getSystemService(Context.TELECOMM_SERVICE);
     }
-
-    /** {@hide} */
-    public ComponentName getSystemPhoneApplication() {
-        try {
-            return mService.getSystemPhoneApplication();
-        } catch (RemoteException e) {
-            Log.e(TAG, e, "Error calling ITelecommService#getSystemPhoneApplication");
-            return null;
-        }
-    }
 }
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index dc2b869..c758c6d 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -17,7 +17,6 @@
 package com.android.internal.telecomm;
 
 import android.telecomm.Subscription;
-import android.content.ComponentName;
 
 /**
  * Interface used to interact with Telecomm. Mostly this is used by TelephonyManager for passing
@@ -43,11 +42,6 @@
     void showCallScreen(boolean showDialpad);
 
     /**
-     * Returns the component name of the phone application installed on the system partition.
-     */
-    ComponentName getSystemPhoneApplication();
-
-    /**
      * Gets a list of Subscriptions.
      */
     List<Subscription> getSubscriptions();
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 9e975e9..53429b6 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -223,6 +223,17 @@
     void injectSmsPdu(in byte[] pdu, String format, in PendingIntent receivedIntent);
 
     /**
+     * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary.
+     * This outbound message was handled by the carrier app. If the carrier app fails to send
+     * this message, it would be resent by PSTN.
+     *
+     * @param messageRef the reference number of the SMS message.
+     * @param success True if and only if the message was sent successfully. If its value is
+     *  false, this message should be resent via PSTN.
+     */
+    void updateSmsSendStatus(int messageRef, boolean success);
+
+    /**
      * Send a multi-part text based SMS.
      *
      * @param destinationAddress the address to send the message to
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index a3b32b3..1d10729 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -44,6 +44,7 @@
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.UserHandle;
@@ -724,4 +725,20 @@
     public PackageInstaller getPackageInstaller() {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void addCrossProfileIntentsForPackage(String packageName, int sourceUserId,
+            int targetUserId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    public Bitmap getUserIcon(int userId) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml
new file mode 100644
index 0000000..7012f4b
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:ordering="sequentially" >
+
+    <objectAnimator
+        android:duration="3000"
+        android:propertyName="pathData"
+        android:valueFrom="@string/triangle"
+        android:valueTo="@string/rectangle"
+        android:valueType="pathType"/>
+
+    <objectAnimator
+        android:duration="3000"
+        android:propertyName="pathData"
+        android:valueFrom="@string/rectangle2"
+        android:valueTo="@string/equal2"
+        android:valueType="pathType"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
index 0900b7c..b37b19f 100644
--- a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
@@ -19,9 +19,13 @@
     <target
         android:name="pie1"
         android:animation="@anim/trim_path_animation01" />
+
     <target
         android:name="v"
         android:animation="@anim/trim_path_animation02" />
+    <target
+        android:name="v"
+        android:animation="@anim/trim_path_animation05" />
 
     <target
         android:name="rotationGroup"
@@ -36,4 +40,4 @@
         android:name="rotationGroup"
         android:animation="@anim/trim_path_animation04" />
 
-</animated-vector>
\ No newline at end of file
+</animated-vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index e28ec41..a212def 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -32,27 +32,21 @@
             android:name="pie1"
             android:fill="#00000000"
             android:pathData="M300,70 a230,230 0 1,0 1,0 z"
-            android:stroke="#FF00FF00"
+            android:stroke="#FF777777"
             android:strokeWidth="70"
             android:trimPathEnd=".75"
             android:trimPathOffset="0"
             android:trimPathStart="0" />
         <path
             android:name="v"
-            android:fill="#FF00FF00"
-            android:pathData="M300,70 l 0,-70 70,70 -70,70z" />
+            android:fill="#000000"
+            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
 
         <group
             android:name="translateToCenterGroup"
             android:rotation="0.0"
             android:translateX="200.0"
             android:translateY="200.0" >
-            <path
-                android:name="twoLines"
-                android:pathData="@string/twoLinePathData"
-                android:stroke="#FFFF0000"
-                android:strokeWidth="20" />
-
             <group
                 android:name="rotationGroup2"
                 android:pivotX="0.0"
@@ -61,7 +55,7 @@
                 <path
                     android:name="twoLines1"
                     android:pathData="@string/twoLinePathData"
-                    android:stroke="#FF00FF00"
+                    android:stroke="#FFFF0000"
                     android:strokeWidth="20" />
 
                 <group
diff --git a/tests/VectorDrawableTest/res/values/strings.xml b/tests/VectorDrawableTest/res/values/strings.xml
index b49a1aa..6ae3d7f 100644
--- a/tests/VectorDrawableTest/res/values/strings.xml
+++ b/tests/VectorDrawableTest/res/values/strings.xml
@@ -16,4 +16,11 @@
 
 <resources>
     <string name="twoLinePathData" >"M 0,0 v 100 M 0,0 h 100"</string>
+
+    <string name="triangle" > "M300,70 l 0,-70 70,70 0,0   -70,70z"</string>
+    <string name="rectangle" >"M300,70 l 0,-70 70,0  0,140 -70,0 z"</string>
+
+    <string name="rectangle2" >"M300,70 l 0,-70 70,0  0,70z M300,70  l 70,0 0,70 -70,0z"</string>
+    <string name="equal2" >    "M300,35 l 0,-35 70,0  0,35z M300,105 l 70,0 0,35 -70,0z"</string>
+
 </resources>
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back.png
index 84e6bc8..b28624f 100644
--- a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back.png
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home.png
index 38e4f45..3f3e288 100644
--- a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home.png
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent.png
index bf9f300..06dcd20 100644
--- a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent.png
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png
index 782ebfe..e464347 100644
--- a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index 677b471..0000000
--- a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png
index a1b8062..1b578a6 100644
--- a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index fcdbefe..0000000
--- a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png
index 633d864..373e84a 100644
--- a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png
+++ b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 4665e2a..0000000
--- a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back.png
index a00bc5b..f878093 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home.png
index dc3183b..8e9583b 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent.png
index b07f611..e2a89c3 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back.png
index bd60cd6..ec2951d 100644
--- a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back.png
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home.png
index c5bc5c9..254f757 100644
--- a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home.png
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent.png
index f621d9c..8a8e941 100644
--- a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent.png
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 6ee307e..c7c2e97 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -81,8 +81,8 @@
     private float mTextScaleX;
     private float mTextSkewX;
     private int mHintingMode = Paint.HINTING_ON;
-    // Variant of the font.
-    private FontVariant mFontVariant = FontVariant.NONE;
+    // Variant of the font. A paint's variant can only be compact or elegant.
+    private FontVariant mFontVariant = FontVariant.COMPACT;
 
     private Xfermode_Delegate mXfermode;
     private ColorFilter_Delegate mColorFilter;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 908bb64..20ccd0c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -70,28 +70,46 @@
         return sManager.getDelegate(nativeTypeface);
     }
 
+    /**
+     * Return a list of fonts that match the style and variant. The list is ordered according to
+     * preference of fonts.
+     *
+     * @param variant The variant preferred. Can only be {@link FontVariant#COMPACT} or
+     *                {@link FontVariant#ELEGANT}
+     */
     public List<Font> getFonts(FontVariant variant) {
+        assert variant != FontVariant.NONE;
         List<Font> fonts = new ArrayList<Font>(mFontFamilies.length);
-        // If we are unable to find fonts matching the variant, we return the fonts from the
-        // other variant since we always want to draw something, rather than nothing.
-        // TODO: check this behaviour with platform.
-        List<Font> otherVariantFonts = new ArrayList<Font>();
-        for (FontFamily_Delegate ffd : mFontFamilies) {
+        for (int i = 0; i < mFontFamilies.length; i++) {
+            FontFamily_Delegate ffd = mFontFamilies[i];
             if (ffd != null) {
                 Font font = ffd.getFont(mStyle);
                 if (font != null) {
-                    if (ffd.getVariant() == variant || ffd.getVariant() == FontVariant.NONE) {
+                    FontVariant ffdVariant = ffd.getVariant();
+                    if (ffdVariant == FontVariant.NONE) {
+                        fonts.add(font);
+                        continue;
+                    }
+                    // We cannot open each font and get locales supported, etc to match the fonts.
+                    // As a workaround, we hardcode certain assumptions like Elegant and Compact
+                    // always appear in pairs.
+                    assert i < mFontFamilies.length - 1;
+                    FontFamily_Delegate ffd2 = mFontFamilies[++i];
+                    assert ffd2 != null;
+                    FontVariant ffd2Variant = ffd2.getVariant();
+                    Font font2 = ffd2.getFont(mStyle);
+                    assert ffd2Variant != FontVariant.NONE && ffd2Variant != ffdVariant
+                            && font2 != null;
+                    // Add the font with the matching variant to the list.
+                    if (variant == ffd.getVariant()) {
                         fonts.add(font);
                     } else {
-                        otherVariantFonts.add(font);
+                        fonts.add(font2);
                     }
                 }
             }
         }
-        if (fonts.size() > 0) {
-            return fonts;
-        }
-        return otherVariantFonts;
+        return fonts;
     }
 
     // ---- native methods ----
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 777471d..59b48e4 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -373,19 +373,19 @@
     public static int GOOD_RSSI_24 = -65;
 
     /** @hide **/
-    public static int LOW_RSSI_24 = -75;
+    public static int LOW_RSSI_24 = -77;
 
     /** @hide **/
     public static int BAD_RSSI_24 = -87;
 
     /** @hide **/
-    public static int GOOD_RSSI_5 = -55;
+    public static int GOOD_RSSI_5 = -60;
 
     /** @hide **/
-    public static int LOW_RSSI_5 = -65;
+    public static int LOW_RSSI_5 = -72;
 
     /** @hide **/
-    public static int BAD_RSSI_5 = -75;
+    public static int BAD_RSSI_5 = -82;
 
     /** @hide **/
     public static int UNWANTED_BLACKLIST_SOFT_BUMP = 4;
@@ -419,6 +419,15 @@
      * 5GHz band is penalized if the 5GHz RSSI is lower than this threshold **/
     public static int G_BAND_PREFERENCE_RSSI_THRESHOLD = -75;
 
+    /** @hide
+     * Boost given to RSSI on a home network for the purpose of calculating the score
+     * This adds stickiness to home networks, as defined by:
+     * - less than 4 known BSSIDs
+     * - PSK only
+     * - TODO: add a test to verify that all BSSIDs are behind same gateway
+     ***/
+    public static int HOME_NETWORK_RSSI_BOOST = 5;
+
     /**
      * @hide
      * A summary of the RSSI and Band status for that configuration