Merge "Fix typo in documentation"
diff --git a/Android.mk b/Android.mk
index 57091cc..5c48dfe 100644
--- a/Android.mk
+++ b/Android.mk
@@ -162,6 +162,7 @@
 	core/java/android/os/ICancellationSignal.aidl \
 	core/java/android/os/IHardwareService.aidl \
 	core/java/android/os/IMessenger.aidl \
+	core/java/android/os/INetworkActivityListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/IPermissionController.aidl \
 	core/java/android/os/IPowerManager.aidl \
@@ -261,23 +262,23 @@
 	media/java/android/media/IAudioService.aidl \
 	media/java/android/media/IAudioFocusDispatcher.aidl \
 	media/java/android/media/IAudioRoutesObserver.aidl \
-	media/java/android/media/IMediaController.aidl \
-	media/java/android/media/IMediaControllerCallback.aidl \
 	media/java/android/media/IMediaHTTPConnection.aidl \
 	media/java/android/media/IMediaHTTPService.aidl \
 	media/java/android/media/IMediaRouterClient.aidl \
 	media/java/android/media/IMediaRouterService.aidl \
 	media/java/android/media/IMediaScannerListener.aidl \
 	media/java/android/media/IMediaScannerService.aidl \
-	media/java/android/media/IMediaSession.aidl \
-	media/java/android/media/IMediaSessionCallback.aidl \
-	media/java/android/media/IMediaSessionManager.aidl \
 	media/java/android/media/IRemoteControlClient.aidl \
 	media/java/android/media/IRemoteControlDisplay.aidl \
 	media/java/android/media/IRemoteDisplayCallback.aidl \
 	media/java/android/media/IRemoteDisplayProvider.aidl \
 	media/java/android/media/IRemoteVolumeObserver.aidl \
 	media/java/android/media/IRingtonePlayer.aidl \
+	media/java/android/media/session/IMediaController.aidl \
+	media/java/android/media/session/IMediaControllerCallback.aidl \
+	media/java/android/media/session/IMediaSession.aidl \
+	media/java/android/media/session/IMediaSessionCallback.aidl \
+	media/java/android/media/session/IMediaSessionManager.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1e49fcbb..448b03d 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -186,6 +186,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/framework-res_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/print/IPrintClient.*)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java/android/media/IMedia*)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/api/current.txt b/api/current.txt
index f03023a..2fb75cb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -345,7 +345,7 @@
     field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
     field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
     field public static final deprecated int capitalize = 16843113; // 0x1010169
-    field public static final int castsShadow = 16843777; // 0x1010401
+    field public static final int castsShadow = 16843775; // 0x10103ff
     field public static final int category = 16843752; // 0x10103e8
     field public static final int centerBright = 16842956; // 0x10100cc
     field public static final int centerColor = 16843275; // 0x101020b
@@ -542,7 +542,6 @@
     field public static final int fromAlpha = 16843210; // 0x10101ca
     field public static final int fromDegrees = 16843187; // 0x10101b3
     field public static final int fromScene = 16843741; // 0x10103dd
-    field public static final int fromSceneName = 16843773; // 0x10103fd
     field public static final int fromXDelta = 16843206; // 0x10101c6
     field public static final int fromXScale = 16843202; // 0x10101c2
     field public static final int fromYDelta = 16843208; // 0x10101c8
@@ -890,7 +889,7 @@
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
     field public static final int requiredForAllUsers = 16843728; // 0x10103d0
-    field public static final int requiredForProfile = 16843778; // 0x1010402
+    field public static final int requiredForProfile = 16843776; // 0x1010400
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
     field public static final int resizeMode = 16843619; // 0x1010363
@@ -961,7 +960,7 @@
     field public static final int shadowRadius = 16843108; // 0x1010164
     field public static final int shape = 16843162; // 0x101019a
     field public static final int shareInterpolator = 16843195; // 0x10101bb
-    field public static final int sharedElementName = 16843775; // 0x10103ff
+    field public static final int sharedElementName = 16843773; // 0x10103fd
     field public static final int sharedUserId = 16842763; // 0x101000b
     field public static final int sharedUserLabel = 16843361; // 0x1010261
     field public static final int shouldDisableView = 16843246; // 0x10101ee
@@ -1145,7 +1144,6 @@
     field public static final int toAlpha = 16843211; // 0x10101cb
     field public static final int toDegrees = 16843188; // 0x10101b4
     field public static final int toScene = 16843742; // 0x10103de
-    field public static final int toSceneName = 16843774; // 0x10103fe
     field public static final int toXDelta = 16843207; // 0x10101c7
     field public static final int toXScale = 16843203; // 0x10101c3
     field public static final int toYDelta = 16843209; // 0x10101c9
@@ -1161,7 +1159,7 @@
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
     field public static final int transition = 16843743; // 0x10103df
-    field public static final int transitionGroup = 16843776; // 0x1010400
+    field public static final int transitionGroup = 16843774; // 0x10103fe
     field public static final int transitionOrdering = 16843744; // 0x10103e0
     field public static final int translationX = 16843554; // 0x1010322
     field public static final int translationY = 16843555; // 0x1010323
@@ -3041,7 +3039,6 @@
     method public int getTaskId();
     method public final java.lang.CharSequence getTitle();
     method public final int getTitleColor();
-    method public android.os.Bundle getTransitionArgs();
     method public final int getVolumeControlStream();
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
@@ -3063,6 +3060,8 @@
     method public void onAttachFragment(android.app.Fragment);
     method public void onAttachedToWindow();
     method public void onBackPressed();
+    method public void onCaptureSharedElementEnd();
+    method public void onCaptureSharedElementStart(android.transition.Transition);
     method protected void onChildTitleChanged(android.app.Activity, java.lang.CharSequence);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onContentChanged();
@@ -3137,7 +3136,6 @@
     method public void setContentView(android.view.View);
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public final void setDefaultKeyMode(int);
-    method public void setEarlyBackgroundTransition(boolean);
     method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable);
     method public final void setFeatureDrawableAlpha(int, int);
     method public final void setFeatureDrawableResource(int, int);
@@ -3178,7 +3176,6 @@
     method public boolean startNextMatchingActivity(android.content.Intent);
     method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
-    method protected void startSharedElementTransition(android.os.Bundle);
     method public deprecated void stopManagingCursor(android.database.Cursor);
     method public void takeKeyEvents(boolean);
     method public void triggerSearch(java.lang.String, android.os.Bundle);
@@ -3349,7 +3346,8 @@
   public class ActivityOptions {
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
     method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
-    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.os.Bundle);
+    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.view.View, java.lang.String);
+    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.util.Pair<android.view.View, java.lang.String>...);
     method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
@@ -10387,6 +10385,7 @@
     method public final android.graphics.Paint getPaint();
     method public android.graphics.Shader.TileMode getTileModeX();
     method public android.graphics.Shader.TileMode getTileModeY();
+    method public android.content.res.ColorStateList getTint();
     method public boolean hasAntiAlias();
     method public boolean hasMipMap();
     method public final boolean isAutoMirrored();
@@ -10402,7 +10401,6 @@
     method public void setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode);
     method public final void setTileModeY(android.graphics.Shader.TileMode);
     method public void setTint(android.content.res.ColorStateList);
-    method public void setTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
@@ -10445,6 +10443,7 @@
     method public final android.graphics.Rect getBounds();
     method public android.graphics.drawable.Drawable.Callback getCallback();
     method public int getChangingConfigurations();
+    method public android.graphics.ColorFilter getColorFilter();
     method public android.graphics.drawable.Drawable.ConstantState getConstantState();
     method public android.graphics.drawable.Drawable getCurrent();
     method public int getIntrinsicHeight();
@@ -10633,13 +10632,13 @@
     method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public android.graphics.Paint getPaint();
+    method public android.content.res.ColorStateList getTint();
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void setTargetDensity(android.graphics.Canvas);
     method public void setTargetDensity(android.util.DisplayMetrics);
     method public void setTargetDensity(int);
     method public void setTint(android.content.res.ColorStateList);
-    method public void setTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class PaintDrawable extends android.graphics.drawable.ShapeDrawable {
@@ -10708,6 +10707,7 @@
     method public android.graphics.Paint getPaint();
     method public android.graphics.drawable.ShapeDrawable.ShaderFactory getShaderFactory();
     method public android.graphics.drawable.shapes.Shape getShape();
+    method public android.content.res.ColorStateList getTint();
     method protected boolean inflateTag(java.lang.String, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet);
     method protected void onDraw(android.graphics.drawable.shapes.Shape, android.graphics.Canvas, android.graphics.Paint);
     method public void setAlpha(int);
@@ -10718,6 +10718,7 @@
     method public void setPadding(android.graphics.Rect);
     method public void setShaderFactory(android.graphics.drawable.ShapeDrawable.ShaderFactory);
     method public void setShape(android.graphics.drawable.shapes.Shape);
+    method public void setTint(android.content.res.ColorStateList);
   }
 
   public static abstract class ShapeDrawable.ShaderFactory {
@@ -11825,6 +11826,20 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public class UsbConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAttributes();
+    method public int getId();
+    method public android.hardware.usb.UsbInterface getInterface(int);
+    method public int getInterfaceCount();
+    method public int getMaxPower();
+    method public java.lang.String getName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ATTR_REMOTE_WAKEUP_MASK = 32; // 0x20
+    field public static final int ATTR_SELF_POWERED_MASK = 64; // 0x40
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public final class UsbConstants {
     ctor public UsbConstants();
     field public static final int USB_CLASS_APP_SPEC = 254; // 0xfe
@@ -11864,6 +11879,8 @@
 
   public class UsbDevice implements android.os.Parcelable {
     method public int describeContents();
+    method public android.hardware.usb.UsbConfiguration getConfiguration(int);
+    method public int getConfigurationCount();
     method public int getDeviceClass();
     method public int getDeviceId();
     method public static int getDeviceId(java.lang.String);
@@ -11894,6 +11911,8 @@
     method public java.lang.String getSerial();
     method public boolean releaseInterface(android.hardware.usb.UsbInterface);
     method public android.hardware.usb.UsbRequest requestWait();
+    method public boolean setConfiguration(android.hardware.usb.UsbConfiguration);
+    method public boolean setInterface(android.hardware.usb.UsbInterface);
   }
 
   public class UsbEndpoint implements android.os.Parcelable {
@@ -11911,12 +11930,14 @@
 
   public class UsbInterface implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAlternateSetting();
     method public android.hardware.usb.UsbEndpoint getEndpoint(int);
     method public int getEndpointCount();
     method public int getId();
     method public int getInterfaceClass();
     method public int getInterfaceProtocol();
     method public int getInterfaceSubclass();
+    method public java.lang.String getName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
@@ -13174,23 +13195,6 @@
     method public static final android.media.MediaCodecInfo getCodecInfoAt(int);
   }
 
-  public final class MediaController {
-    ctor public MediaController(android.media.MediaSessionToken);
-    method public void addCallback(android.media.MediaController.Callback);
-    method public void addCallback(android.media.MediaController.Callback, android.os.Handler);
-    method public void removeCallback(android.media.MediaController.Callback);
-    method public void sendCommand(java.lang.String, android.os.Bundle);
-    method public void sendMediaButton(int);
-  }
-
-  public static abstract class MediaController.Callback {
-    ctor public MediaController.Callback();
-    method public void onEvent(java.lang.String, android.os.Bundle);
-    method public void onMetadataUpdate(android.os.Bundle);
-    method public void onPlaybackStateChange(int);
-    method public void onRouteChanged(android.os.Bundle);
-  }
-
   public final class MediaCrypto {
     ctor public MediaCrypto(java.util.UUID, byte[]) throws android.media.MediaCryptoException;
     method public static final boolean isCryptoSchemeSupported(java.util.UUID);
@@ -13757,33 +13761,6 @@
     method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
   }
 
-  public final class MediaSession {
-    method public void addCallback(android.media.MediaSession.Callback);
-    method public void addCallback(android.media.MediaSession.Callback, android.os.Handler);
-    method public android.media.MediaSessionToken getSessionToken();
-    method public void release();
-    method public void removeCallback(android.media.MediaSession.Callback);
-    method public void setPlaybackState(int);
-  }
-
-  public static abstract class MediaSession.Callback {
-    ctor public MediaSession.Callback();
-    method public void onCommand(java.lang.String, android.os.Bundle);
-    method public void onMediaButton(android.content.Intent);
-    method public void onRequestRouteChange(android.os.Bundle);
-  }
-
-  public final class MediaSessionManager {
-    method public android.media.MediaSession createSession(java.lang.String);
-    method public java.util.List<android.media.MediaController> getActiveSessions();
-  }
-
-  public class MediaSessionToken implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
   public class MediaSyncEvent {
     method public static android.media.MediaSyncEvent createEvent(int) throws java.lang.IllegalArgumentException;
     method public int getAudioSessionId();
@@ -14453,6 +14430,54 @@
 
 }
 
+package android.media.session {
+
+  public final class MediaController {
+    ctor public MediaController(android.media.session.MediaSessionToken);
+    method public void addCallback(android.media.session.MediaController.Callback);
+    method public void addCallback(android.media.session.MediaController.Callback, android.os.Handler);
+    method public void removeCallback(android.media.session.MediaController.Callback);
+    method public void sendCommand(java.lang.String, android.os.Bundle);
+    method public void sendMediaButton(int);
+  }
+
+  public static abstract class MediaController.Callback {
+    ctor public MediaController.Callback();
+    method public void onEvent(java.lang.String, android.os.Bundle);
+    method public void onMetadataUpdate(android.os.Bundle);
+    method public void onPlaybackStateChange(int);
+    method public void onRouteChanged(android.os.Bundle);
+  }
+
+  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);
+    method public android.media.session.MediaSessionToken getSessionToken();
+    method public void release();
+    method public void removeCallback(android.media.session.MediaSession.Callback);
+    method public void setPlaybackState(int);
+  }
+
+  public static abstract class MediaSession.Callback {
+    ctor public MediaSession.Callback();
+    method public void onCommand(java.lang.String, android.os.Bundle);
+    method public void onMediaButton(android.content.Intent);
+    method public void onRequestRouteChange(android.os.Bundle);
+  }
+
+  public final class MediaSessionManager {
+    method public android.media.session.MediaSession createSession(java.lang.String);
+    method public java.util.List<android.media.session.MediaController> getActiveSessions();
+  }
+
+  public class MediaSessionToken implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+}
+
 package android.mtp {
 
   public final class MtpConstants {
@@ -14589,11 +14614,14 @@
     method public android.net.NetworkInfo getNetworkInfo(int);
     method public int getNetworkPreference();
     method public boolean isActiveNetworkMetered();
+    method public boolean isNetworkActive();
     method public static boolean isNetworkTypeValid(int);
+    method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
     method public boolean requestRouteToHost(int, int);
     method public void setNetworkPreference(int);
     method public int startUsingNetworkFeature(int, java.lang.String);
     method public int stopUsingNetworkFeature(int, java.lang.String);
+    method public void unregisterNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
     field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
     field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
@@ -14616,6 +14644,10 @@
     field public static final int TYPE_WIMAX = 6; // 0x6
   }
 
+  public static abstract interface ConnectivityManager.OnNetworkActiveListener {
+    method public abstract void onNetworkActive();
+  }
+
   public class Credentials {
     ctor public Credentials(int, int, int);
     method public int getGid();
@@ -15512,6 +15544,7 @@
     method public int describeContents();
     method public java.lang.String getBSSID();
     method public static android.net.NetworkInfo.DetailedState getDetailedStateOf(android.net.wifi.SupplicantState);
+    method public int getFrequency();
     method public boolean getHiddenSSID();
     method public int getIpAddress();
     method public int getLinkSpeed();
@@ -15521,6 +15554,7 @@
     method public java.lang.String getSSID();
     method public android.net.wifi.SupplicantState getSupplicantState();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String FREQUENCY_UNITS = "MHz";
     field public static final java.lang.String LINK_SPEED_UNITS = "Mbps";
   }
 
@@ -16301,8 +16335,10 @@
   }
 
   public abstract class EGLObjectHandle {
-    ctor protected EGLObjectHandle(int);
-    method public int getHandle();
+    ctor protected deprecated EGLObjectHandle(int);
+    ctor protected EGLObjectHandle(long);
+    method public deprecated int getHandle();
+    method public long getNativeHandle();
   }
 
   public class EGLSurface extends android.opengl.EGLObjectHandle {
@@ -26820,15 +26856,11 @@
     ctor public TransitionManager();
     method public static void beginDelayedTransition(android.view.ViewGroup);
     method public static void beginDelayedTransition(android.view.ViewGroup, android.transition.Transition);
-    method public android.transition.Transition getNamedTransition(java.lang.String, android.transition.Scene);
-    method public android.transition.Transition getNamedTransition(android.transition.Scene, java.lang.String);
-    method public java.lang.String[] getTargetSceneNames(android.transition.Scene);
     method public static void go(android.transition.Scene);
     method public static void go(android.transition.Scene, android.transition.Transition);
+    method public void setExitTransition(android.transition.Scene, android.transition.Transition);
     method public void setTransition(android.transition.Scene, android.transition.Transition);
     method public void setTransition(android.transition.Scene, android.transition.Scene, android.transition.Transition);
-    method public void setTransition(android.transition.Scene, java.lang.String, android.transition.Transition);
-    method public void setTransition(java.lang.String, android.transition.Scene, android.transition.Transition);
     method public void transitionTo(android.transition.Scene);
   }
 
@@ -29799,6 +29831,7 @@
     method public abstract boolean isFloating();
     method public abstract boolean isShortcutKey(int, android.view.KeyEvent);
     method public final void makeActive();
+    method public void mapTransitionTargets(java.util.Map<java.lang.String, java.lang.String>);
     method protected abstract void onActive();
     method public abstract void onConfigurationChanged(android.content.res.Configuration);
     method public abstract void openPanel(int, android.view.KeyEvent);
@@ -29837,6 +29870,7 @@
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract deprecated void setTitleColor(int);
     method public void setTransitionManager(android.transition.TransitionManager);
+    method public void setTriggerEarlyEnterTransition(boolean);
     method public void setType(int);
     method public void setUiOptions(int);
     method public void setUiOptions(int, int);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 89e15d2..01e7615 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -232,6 +232,8 @@
                 "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
                 "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
                 "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
+                "    [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" +
+                "        (to embed a comma into a string escape it using \"\\,\")\n" +
                 "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
                 "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
                 "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
@@ -419,6 +421,15 @@
                 }
                 intent.putExtra(key, list);
                 hasIntentInfo = true;
+            } else if (opt.equals("--esa")) {
+                String key = nextArgRequired();
+                String value = nextArgRequired();
+                // Split on commas unless they are preceeded by an escape.
+                // The escape character must be escaped for the string and
+                // again for the regex, thus four escape characters become one.
+                String[] strings = value.split("(?<!\\\\),");
+                intent.putExtra(key, strings);
+                hasIntentInfo = true;
             } else if (opt.equals("--ez")) {
                 String key = nextArgRequired();
                 String value = nextArgRequired();
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index d5ff84e..a4e2718 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -19,9 +19,6 @@
     libGLESv1_CM \
     libgui
 
-LOCAL_C_INCLUDES := \
-	$(call include-path-for, corecg graphics)
-
 LOCAL_MODULE:= bootanimation
 
 
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 125bea6..e12e961c 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -42,9 +42,9 @@
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
-#include <core/SkBitmap.h>
-#include <core/SkStream.h>
-#include <core/SkImageDecoder.h>
+#include <SkBitmap.h>
+#include <SkStream.h>
+#include <SkImageDecoder.h>
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk
index ca8008b..5c11b75 100644
--- a/cmds/screencap/Android.mk
+++ b/cmds/screencap/Android.mk
@@ -16,11 +16,4 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_C_INCLUDES += \
-	external/skia/include/core \
-	external/skia/include/effects \
-	external/skia/include/images \
-	external/skia/src/ports \
-	external/skia/include/utils
-
 include $(BUILD_EXECUTABLE)
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9a3c290..3297fe0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.transition.Scene;
+import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
 import android.util.SuperNotCalledException;
@@ -3316,7 +3317,7 @@
             @Nullable Bundle appSearchData, boolean globalSearch) {
         ensureSearchManager();
         mSearchManager.startSearch(initialQuery, selectInitialQuery, getComponentName(),
-                        appSearchData, globalSearch); 
+                appSearchData, globalSearch); 
     }
 
     /**
@@ -3446,7 +3447,11 @@
      * @see #startActivity
      */
     public void startActivityForResult(Intent intent, int requestCode) {
-        startActivityForResult(intent, requestCode, null);
+        Bundle options = null;
+        if (mWindow.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+            options = ActivityOptions.makeSceneTransitionAnimation(null).toBundle();
+        }
+        startActivityForResult(intent, requestCode, options);
     }
 
     /**
@@ -3484,12 +3489,15 @@
      * @see #startActivity
      */
     public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
-        TransitionManager tm = getContentTransitionManager();
-        if (tm != null && options != null) {
+        if (options != null) {
             ActivityOptions activityOptions = new ActivityOptions(options);
             if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
-                getWindow().startExitTransition(activityOptions);
-                options = activityOptions.toBundle();
+                if (mActionBar != null) {
+                    ArrayMap<String, View> sharedElementMap = new ArrayMap<String, View>();
+                    mActionBar.captureSharedElements(sharedElementMap);
+                    activityOptions.addSharedElements(sharedElementMap);
+                }
+                options = mWindow.startExitTransition(activityOptions);
             }
         }
         if (mParent == null) {
@@ -3664,7 +3672,7 @@
      */
     @Override
     public void startActivity(Intent intent) {
-        startActivity(intent, null);
+        this.startActivity(intent, null);
     }
 
     /**
@@ -4720,7 +4728,8 @@
      */
     public final void setProgressBarIndeterminate(boolean indeterminate) {
         getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
-                indeterminate ? Window.PROGRESS_INDETERMINATE_ON : Window.PROGRESS_INDETERMINATE_OFF);
+                indeterminate ? Window.PROGRESS_INDETERMINATE_ON
+                        : Window.PROGRESS_INDETERMINATE_OFF);
     }
     
     /**
@@ -5330,12 +5339,6 @@
                 mTransitionActivityOptions = activityOptions;
                 sceneTransitionListener = new Window.SceneTransitionListener() {
                     @Override
-                    public void enterSharedElement(Bundle transitionArgs) {
-                        startSharedElementTransition(transitionArgs);
-                        mTransitionActivityOptions = null;
-                    }
-
-                    @Override
                     public void nullPendingTransition() {
                         overridePendingTransition(0, 0);
                     }
@@ -5349,6 +5352,16 @@
                     public void convertToTranslucent() {
                         Activity.this.convertToTranslucent(null);
                     }
+
+                    @Override
+                    public void sharedElementStart(Transition transition) {
+                        Activity.this.onCaptureSharedElementStart(transition);
+                    }
+
+                    @Override
+                    public void sharedElementEnd() {
+                        Activity.this.onCaptureSharedElementEnd();
+                    }
                 };
 
             }
@@ -5542,53 +5555,23 @@
     }
 
     /**
-     * Gets the entering Activity transition args. Will be null if
-     * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)} was
-     * not used to pass a Bundle to startActivity. The Bundle passed to that method in the
-     * calling Activity is returned here.
-     * <p>After startSharedElementTransition is called, this method will return null.</p>
+     * Called when setting up Activity Scene transitions when the start state for shared
+     * elements has been captured. Override this method to modify the start position of shared
+     * elements for the entry Transition.
      *
-     * @return The Bundle passed into Bundle parameter of
-     *         {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)}
-     *         in the calling Activity.
+     * @param transition The <code>Transition</code> being used to change
+     *                   bounds of shared elements in the source Activity to
+     *                   the bounds defined by the entering Scene.
      */
-    public Bundle getTransitionArgs() {
-        if (mTransitionActivityOptions == null) {
-            return null;
-        }
-        return mTransitionActivityOptions.getSceneTransitionArgs();
+    public void onCaptureSharedElementStart(Transition transition) {
     }
 
     /**
-     * Override to transfer a shared element from a calling Activity to this Activity.
-     * Shared elements will be made VISIBLE before this call. The Activity is responsible
-     * for transitioning the shared elements from their location to the eventual destination.
-     * The shared element will be laid out a the destination when this method is called.
-     *
-     * @param transitionArgs The same as returned from {@link #getTransitionArgs()}, this should
-     *                       contain information from the calling Activity to tell where the
-     *                       shared element should be placed.
+     * Called when setting up Activity Scene transitions when the final state for
+     * shared elements state has been captured. Override this method to modify the destination
+     * position of shared elements for the entry Transition.
      */
-    protected void startSharedElementTransition(Bundle transitionArgs) {
-    }
-
-    /**
-     * Controls how the background fade is triggered when there is an entering Activity transition.
-     * If fadeEarly is true, the Window background will fade in as soon as the shared elements are
-     * ready to switch. If fadeEarly is false, the background will fade only after the calling
-     * Activity's exit transition completes. By default, the Window will fade in when the calling
-     * Activity's exit transition completes.
-     *
-     * @param fadeEarly Set to true to fade out the exiting Activity as soon as the shared elements
-     *                  are transferred. Set to false to fade out the exiting Activity as soon as
-     *                  the shared element is transferred.
-     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
-     */
-    public void setEarlyBackgroundTransition(boolean fadeEarly) {
-        if (mTransitionActivityOptions == null) {
-            return;
-        }
-        mWindow.setEarlyBackgroundTransition(fadeEarly);
+    public void onCaptureSharedElementEnd() {
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 04155b5..ea0ddc1 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1843,6 +1843,17 @@
             return true;
         }
 
+        case GET_TAG_FOR_INTENT_SENDER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IIntentSender r = IIntentSender.Stub.asInterface(
+                data.readStrongBinder());
+            String prefix = data.readString();
+            String tag = getTagForIntentSender(r, prefix);
+            reply.writeNoException();
+            reply.writeString(tag);
+            return true;
+        }
+
         case UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             Configuration config = Configuration.CREATOR.createFromParcel(data);
@@ -4435,6 +4446,21 @@
         return res;
     }
 
+    public String getTagForIntentSender(IIntentSender sender, String prefix)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(sender.asBinder());
+        data.writeString(prefix);
+        mRemote.transact(GET_TAG_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        String res = reply.readString();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
     public void updatePersistentConfiguration(Configuration values) throws RemoteException
     {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 3f97c40..07247ff 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -16,7 +16,6 @@
 
 package android.app;
 
-import android.animation.Animator;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.Bundle;
@@ -24,8 +23,8 @@
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.transition.Transition;
-import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Pair;
 import android.view.View;
 
 import java.util.ArrayList;
@@ -100,12 +99,6 @@
     public static final String KEY_ANIM_START_LISTENER = "android:animStartListener";
 
     /**
-     * Arguments for the scene transition about to begin.
-     * @hide
-     */
-    public static final String KEY_SCENE_TRANSITION_ARGS = "android:sceneTransitionArgs";
-
-    /**
      * For Activity transitions, the calling Activity's TransitionListener used to
      * notify the called Activity when the shared element and the exit transitions
      * complete.
@@ -120,9 +113,15 @@
     private static final String KEY_TRANSITION_TARGET_LISTENER = "android:transitionTargetListener";
 
     /**
-     * The shared element's texture ID (TODO: not used yet).
+     * The names of shared elements that are transitioned to the started Activity.
+     * This is also the name of shared elements that the started Activity accepted.
      */
-    private static final String KEY_SHARED_ELEMENT_TEXTURE_ID = "android:sharedElementTextureId";
+    private static final String KEY_SHARED_ELEMENT_NAMES = "android:shared_element_names";
+
+    /**
+     * The shared elements names of the views in the calling Activity.
+     */
+    private static final String KEY_LOCAL_ELEMENT_NAMES = "android:local_element_names";
 
     /** @hide */
     public static final int ANIM_NONE = 0;
@@ -146,9 +145,10 @@
     private int mStartY;
     private int mStartWidth;
     private int mStartHeight;
-    private Bundle mTransitionArgs;
     private IRemoteCallback mAnimationStartedListener;
     private IRemoteCallback mTransitionCompleteListener;
+    private ArrayList<String> mSharedElementNames;
+    private ArrayList<String> mLocalElementNames;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -226,7 +226,7 @@
 
     /** @hide */
     public interface ActivityTransitionTarget {
-        void sharedElementTransitionComplete();
+        void sharedElementTransitionComplete(Bundle transitionArgs);
         void exitTransitionComplete();
     }
 
@@ -348,35 +348,51 @@
     }
 
     /**
-     * Create an ActivityOptions to transition between Activities using cross-Activity animation.
-     * When visual elements are to carry between Activities, args should be used to tell the called
-     * Activity about the location and size.
-     *
-     * TODO: Provide facility to capture layout and bitmap of shared elements.
-     *
-     * <p>When
-     * {@link android.app.Activity#startActivities(android.content.Intent[], android.os.Bundle)}
-     * is used with the {@link #toBundle()} result, the Activity's content scene will automatically
-     * transition out by setting their visibility to {@link View#INVISIBLE}. Shared elements
-     * ({@link android.view.View#setSharedElementName(String)}) are unmodified during the
-     * transition to allow the started Activity to seamlessly take it over. ViewGroups typically
-     * don't transition out, and instead transition out their children unless they have a
-     * background. To modify this behavior, use
-     * {@link android.view.ViewGroup#setTransitionGroup(boolean)}.</p>
+     * Create an ActivityOptions to transition between Activities using cross-Activity scene
+     * animations. This method carries the position of one shared element to the started Activity.
      *
      * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
      * enabled on the calling Activity to cause an exit transition. The same must be in
      * the called Activity to get an entering transition.</p>
-     *
-     * @param args Contains information for transferring a view between this Activity and the
-     *             target Activity. Will be used by the called Activity to transition the
-     *             view to its eventual destination
-     * @see android.app.Activity#startSharedElementTransition(android.os.Bundle)
+     * @param sharedElement The View to transition to the started Activity. sharedElement must
+     *                      have a non-null sharedElementName.
+     * @param sharedElementName The shared element name as used in the target Activity. This may
+     *                          be null if it has the same name as sharedElement.
+     * @return Returns a new ActivityOptions object that you can use to
+     *         supply these options as the options Bundle when starting an activity.
      */
-    public static ActivityOptions makeSceneTransitionAnimation(Bundle args) {
+    public static ActivityOptions makeSceneTransitionAnimation(View sharedElement,
+            String sharedElementName) {
+        return makeSceneTransitionAnimation(
+                new Pair<View, String>(sharedElement, sharedElementName));
+    }
+
+    /**
+     * Create an ActivityOptions to transition between Activities using cross-Activity scene
+     * animations. This method carries the position of multiple shared elements to the started
+     * Activity.
+     *
+     * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
+     * enabled on the calling Activity to cause an exit transition. The same must be in
+     * the called Activity to get an entering transition.</p>
+     * @param sharedElements The View to transition to the started Activity along with the
+     *                       shared element name as used in the started Activity. The view
+     *                       must have a non-null sharedElementName.
+     * @return Returns a new ActivityOptions object that you can use to
+     *         supply these options as the options Bundle when starting an activity.
+     */
+    public static ActivityOptions makeSceneTransitionAnimation(
+            Pair<View, String>... sharedElements) {
         ActivityOptions opts = new ActivityOptions();
         opts.mAnimationType = ANIM_SCENE_TRANSITION;
-        opts.mTransitionArgs = args;
+        opts.mSharedElementNames = new ArrayList<String>();
+        opts.mLocalElementNames = new ArrayList<String>();
+
+        if (sharedElements != null) {
+            for (Pair<View, String> sharedElement : sharedElements) {
+                opts.addSharedElement(sharedElement.first, sharedElement.second);
+            }
+        }
         return opts;
     }
 
@@ -412,9 +428,10 @@
                 break;
 
             case ANIM_SCENE_TRANSITION:
-                mTransitionArgs = opts.getBundle(KEY_SCENE_TRANSITION_ARGS);
                 mTransitionCompleteListener = IRemoteCallback.Stub.asInterface(
                         opts.getBinder(KEY_TRANSITION_COMPLETE_LISTENER));
+                mSharedElementNames = opts.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
+                mLocalElementNames = opts.getStringArrayList(KEY_LOCAL_ELEMENT_NAMES);
                 break;
         }
     }
@@ -465,17 +482,19 @@
     }
 
     /** @hide */
-    public Bundle getSceneTransitionArgs() {
-        return mTransitionArgs;
-    }
-
-    /** @hide */
     public IRemoteCallback getOnAnimationStartListener() {
         return mAnimationStartedListener;
     }
 
     /** @hide */
-    public void dispatchSceneTransitionStarted(final ActivityTransitionTarget target) {
+    public ArrayList<String> getSharedElementNames() { return mSharedElementNames; }
+
+    /** @hide */
+    public ArrayList<String> getLocalElementNames() { return mLocalElementNames; }
+
+    /** @hide */
+    public void dispatchSceneTransitionStarted(final ActivityTransitionTarget target,
+            ArrayList<String> sharedElementNames) {
         boolean listenerSent = false;
         if (mTransitionCompleteListener != null) {
             IRemoteCallback callback = new IRemoteCallback.Stub() {
@@ -484,13 +503,13 @@
                     if (data == null) {
                         target.exitTransitionComplete();
                     } else {
-                        // TODO: Use texture id
-                        target.sharedElementTransitionComplete();
+                        target.sharedElementTransitionComplete(data);
                     }
                 }
             };
             Bundle bundle = new Bundle();
             bundle.putBinder(KEY_TRANSITION_TARGET_LISTENER, callback.asBinder());
+            bundle.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, sharedElementNames);
             try {
                 mTransitionCompleteListener.sendResult(bundle);
                 listenerSent = true;
@@ -499,12 +518,23 @@
             }
         }
         if (!listenerSent) {
-            target.sharedElementTransitionComplete();
+            target.sharedElementTransitionComplete(null);
             target.exitTransitionComplete();
         }
     }
 
     /** @hide */
+    public void dispatchSharedElementsReady() {
+        if (mTransitionCompleteListener != null) {
+            try {
+                mTransitionCompleteListener.sendResult(null);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Couldn't synchronize shared elements", e);
+            }
+        }
+    }
+
+    /** @hide */
     public void abort() {
         if (mAnimationStartedListener != null) {
             try {
@@ -530,6 +560,8 @@
         if (otherOptions.mPackageName != null) {
             mPackageName = otherOptions.mPackageName;
         }
+        mSharedElementNames = null;
+        mLocalElementNames = null;
         switch (otherOptions.mAnimationType) {
             case ANIM_CUSTOM:
                 mAnimationType = otherOptions.mAnimationType;
@@ -544,7 +576,6 @@
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
                 mTransitionCompleteListener = null;
-                mTransitionArgs = null;
                 break;
             case ANIM_SCALE_UP:
                 mAnimationType = otherOptions.mAnimationType;
@@ -560,7 +591,6 @@
                 }
                 mAnimationStartedListener = null;
                 mTransitionCompleteListener = null;
-                mTransitionArgs = null;
                 break;
             case ANIM_THUMBNAIL_SCALE_UP:
             case ANIM_THUMBNAIL_SCALE_DOWN:
@@ -576,14 +606,14 @@
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
                 mTransitionCompleteListener = null;
-                mTransitionArgs = null;
                 break;
             case ANIM_SCENE_TRANSITION:
                 mAnimationType = otherOptions.mAnimationType;
                 mTransitionCompleteListener = otherOptions.mTransitionCompleteListener;
-                mTransitionArgs = otherOptions.mTransitionArgs;
                 mThumbnail = null;
                 mAnimationStartedListener = null;
+                mSharedElementNames = otherOptions.mSharedElementNames;
+                mLocalElementNames = otherOptions.mLocalElementNames;
                 break;
         }
     }
@@ -627,11 +657,12 @@
                 break;
             case ANIM_SCENE_TRANSITION:
                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
-                b.putBundle(KEY_SCENE_TRANSITION_ARGS, mTransitionArgs);
                 if (mTransitionCompleteListener != null) {
                     b.putBinder(KEY_TRANSITION_COMPLETE_LISTENER,
                             mTransitionCompleteListener.asBinder());
                 }
+                b.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, mSharedElementNames);
+                b.putStringArrayList(KEY_LOCAL_ELEMENT_NAMES, mLocalElementNames);
                 break;
         }
         return b;
@@ -652,32 +683,52 @@
     }
 
     /** @hide */
-    public interface SharedElementSource {
-        int getTextureId();
+    public void addSharedElements(Map<String, View> sharedElements) {
+        for (Map.Entry<String, View> entry : sharedElements.entrySet()) {
+            addSharedElement(entry.getValue(), entry.getKey());
+        }
     }
 
-    /**
-     * In the calling Activity when transitioning out, sets the Transition to listen for
-     * changes.
-     * @hide
-     */
-    public void setExitTransition(Transition transition, SharedElementSource sharedElementSource) {
-        mTransitionCompleteListener = new ExitTransitionListener(transition, sharedElementSource);
+    /** @hide */
+    public void updateSceneTransitionAnimation(Transition exitTransition,
+            Transition sharedElementTransition, SharedElementSource sharedElementSource) {
+        mTransitionCompleteListener = new ExitTransitionListener(exitTransition,
+                sharedElementTransition, sharedElementSource);
+    }
+
+    private void addSharedElement(View view, String name) {
+        String sharedElementName = view.getSharedElementName();
+        if (name == null) {
+            name = sharedElementName;
+        }
+        mSharedElementNames.add(name);
+        mLocalElementNames.add(sharedElementName);
+    }
+
+    /** @hide */
+    public interface SharedElementSource {
+        Bundle getSharedElementExitState();
+        void acceptedSharedElements(ArrayList<String> sharedElementNames);
+        void hideSharedElements();
     }
 
     private static class ExitTransitionListener extends IRemoteCallback.Stub
-            implements Transition.TransitionListener, Animator.AnimatorListener {
-        private ArrayList<Animator> mSharedElementAnimators = new ArrayList<Animator>();
+            implements Transition.TransitionListener {
         private boolean mSharedElementNotified;
         private Transition mExitTransition;
+        private Transition mSharedElementTransition;
         private IRemoteCallback mTransitionCompleteCallback;
         private boolean mExitComplete;
+        private boolean mSharedElementComplete;
         private SharedElementSource mSharedElementSource;
 
-        public ExitTransitionListener(Transition transition, SharedElementSource sharedElementSource) {
+        public ExitTransitionListener(Transition exitTransition, Transition sharedElementTransition,
+                SharedElementSource sharedElementSource) {
             mSharedElementSource = sharedElementSource;
-            mExitTransition = transition;
+            mExitTransition = exitTransition;
             mExitTransition.addListener(this);
+            mSharedElementTransition = sharedElementTransition;
+            mSharedElementTransition.addListener(this);
         }
 
         @Override
@@ -685,36 +736,36 @@
             if (data != null) {
                 mTransitionCompleteCallback = IRemoteCallback.Stub.asInterface(
                         data.getBinder(KEY_TRANSITION_TARGET_LISTENER));
+                ArrayList<String> sharedElementNames
+                        = data.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
+                mSharedElementSource.acceptedSharedElements(sharedElementNames);
                 notifySharedElement();
                 notifyExit();
+            } else {
+                mSharedElementSource.hideSharedElements();
             }
         }
 
         @Override
         public void onTransitionStart(Transition transition) {
-            ArrayMap<Animator, Transition.AnimationInfo> runningAnimators
-                    = Transition.getRunningAnimators();
-            for (Map.Entry<Animator, Transition.AnimationInfo> entry : runningAnimators.entrySet()) {
-                if (entry.getValue().view.getSharedElementName() != null) {
-                    mSharedElementAnimators.add(entry.getKey());
-                    entry.getKey().addListener(this);
-                }
-            }
-            notifySharedElement();
         }
 
         @Override
         public void onTransitionEnd(Transition transition) {
-            mExitComplete = true;
-            notifyExit();
-            mExitTransition.removeListener(this);
+            if (transition == mExitTransition) {
+                mExitComplete = true;
+                notifyExit();
+                mExitTransition.removeListener(this);
+            } else {
+                mSharedElementComplete = true;
+                notifySharedElement();
+                mSharedElementTransition.removeListener(this);
+            }
         }
 
         @Override
         public void onTransitionCancel(Transition transition) {
-            mExitComplete = true;
-            notifyExit();
-            mExitTransition.removeListener(this);
+            onTransitionEnd(transition);
         }
 
         @Override
@@ -725,34 +776,13 @@
         public void onTransitionResume(Transition transition) {
         }
 
-        @Override
-        public void onAnimationStart(Animator animation) {
-        }
-
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mSharedElementAnimators.remove(animation);
-            notifySharedElement();
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-            mSharedElementAnimators.remove(animation);
-            notifySharedElement();
-        }
-
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-
         private void notifySharedElement() {
-            if (!mSharedElementNotified && mSharedElementAnimators.isEmpty()
+            if (!mSharedElementNotified && mSharedElementComplete
                     && mTransitionCompleteCallback != null) {
                 mSharedElementNotified = true;
                 try {
-                    Bundle bundle = new Bundle();
-                    bundle.putInt(KEY_SHARED_ELEMENT_TEXTURE_ID, mSharedElementSource.getTextureId());
-                    mTransitionCompleteCallback.sendResult(bundle);
+                    Bundle sharedElementState = mSharedElementSource.getSharedElementExitState();
+                    mTransitionCompleteCallback.sendResult(sharedElementState);
                 } catch (RemoteException e) {
                     Log.w(TAG, "Couldn't notify that the transition ended", e);
                 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7efb3f1..9b3643c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -63,7 +63,7 @@
 import android.location.LocationManager;
 import android.media.AudioManager;
 import android.media.MediaRouter;
-import android.media.MediaSessionManager;
+import android.media.session.MediaSessionManager;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.INetworkPolicyManager;
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index c09da87..6c0d379 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1405,6 +1405,7 @@
         mRestored = false;
         mBackStackNesting = 0;
         mFragmentManager = null;
+        mChildFragmentManager = null;
         mActivity = null;
         mFragmentId = 0;
         mContainerId = 0;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index bf2a629..76f9d97 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1026,6 +1026,7 @@
                                     f.mActivity = null;
                                     f.mParentFragment = null;
                                     f.mFragmentManager = null;
+                                    f.mChildFragmentManager = null;
                                 }
                             }
                         }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index bbf2ecc..4412261 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -367,6 +367,8 @@
 
     public Intent getIntentForIntentSender(IIntentSender sender) throws RemoteException;
 
+    public String getTagForIntentSender(IIntentSender sender, String prefix) throws RemoteException;
+
     public void updatePersistentConfiguration(Configuration values) throws RemoteException;
 
     public long[] getProcessPss(int[] pids) throws RemoteException;
@@ -709,4 +711,8 @@
     int GET_HOME_ACTIVITY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+183;
     int GET_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184;
     int DELETE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+185;
+
+
+    // Start of L transactions
+    int GET_TAG_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+210;
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7926595..b067cd0 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -204,6 +204,15 @@
      */
     public RemoteViews bigContentView;
 
+
+    /**
+     * @hide
+     * A medium-format version of {@link #contentView}, giving the Notification an
+     * opportunity to add action buttons to contentView. The system UI may
+     * choose to show this as a popup notification at its discretion.
+     */
+    public RemoteViews headsUpContentView;
+
     /**
      * The bitmap that may escape the bounds of the panel and bar.
      */
@@ -809,6 +818,10 @@
             bigContentView = RemoteViews.CREATOR.createFromParcel(parcel);
         }
 
+        if (parcel.readInt() != 0) {
+            headsUpContentView = RemoteViews.CREATOR.createFromParcel(parcel);
+        }
+
         visibility = parcel.readInt();
 
         if (parcel.readInt() != 0) {
@@ -899,6 +912,10 @@
             that.bigContentView = this.bigContentView.clone();
         }
 
+        if (heavy && this.headsUpContentView != null) {
+            that.headsUpContentView = this.headsUpContentView.clone();
+        }
+
         that.visibility = this.visibility;
 
         if (this.publicVersion != null) {
@@ -920,6 +937,7 @@
         tickerView = null;
         contentView = null;
         bigContentView = null;
+        headsUpContentView = null;
         largeIcon = null;
         if (extras != null) {
             extras.remove(Notification.EXTRA_LARGE_ICON);
@@ -1032,6 +1050,13 @@
             parcel.writeInt(0);
         }
 
+        if (headsUpContentView != null) {
+            parcel.writeInt(1);
+            headsUpContentView.writeToParcel(parcel, 0);
+        } else {
+            parcel.writeInt(0);
+        }
+
         parcel.writeInt(visibility);
 
         if (publicVersion != null) {
@@ -1182,6 +1207,9 @@
         if (bigContentView != null) {
             bigContentView.setUser(user);
         }
+        if (headsUpContentView != null) {
+            headsUpContentView.setUser(user);
+        }
     }
 
     /**
@@ -1881,6 +1909,13 @@
             return applyStandardTemplateWithActions(R.layout.notification_template_big_base);
         }
 
+        private RemoteViews makeHEadsUpContentView() {
+            if (mActions.size() == 0) return null;
+
+            return applyStandardTemplateWithActions(R.layout.notification_template_big_base);
+        }
+
+
         private RemoteViews generateActionButton(Action action) {
             final boolean tombstone = (action.actionIntent == null);
             RemoteViews button = new RemoteViews(mContext.getPackageName(),
@@ -1921,6 +1956,7 @@
             n.defaults = mDefaults;
             n.flags = mFlags;
             n.bigContentView = makeBigContentView();
+            n.headsUpContentView = makeHEadsUpContentView();
             if (mLedOnMs != 0 || mLedOffMs != 0) {
                 n.flags |= FLAG_SHOW_LIGHTS;
             }
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index d4de112..8efc14f 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -889,6 +889,20 @@
     }
 
     /**
+     * @hide
+     * Return descriptive tag for this PendingIntent.
+     */
+    public String getTag(String prefix) {
+        try {
+            return ActivityManagerNative.getDefault()
+                .getTagForIntentSender(mTarget, prefix);
+        } catch (RemoteException e) {
+            // Should never happen.
+            return null;
+        }
+    }
+
+    /**
      * Comparison operator on two PendingIntent objects, such that true
      * is returned then they both represent the same operation from the
      * same package.  This allows you to use {@link #getActivity},
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d05d1a1..81a886a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2352,10 +2352,10 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.media.MediaSessionManager} for managing media Sessions.
+     * {@link android.media.session.MediaSessionManager} for managing media Sessions.
      *
      * @see #getSystemService
-     * @see android.media.MediaSessionManager
+     * @see android.media.session.MediaSessionManager
      */
     public static final String MEDIA_SESSION_SERVICE = "media_session";
 
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 352825f..a41b4f9 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -539,7 +539,7 @@
          * @hide
          */
         public final int getAssetInt() {
-            return (int) mAsset;
+            throw new UnsupportedOperationException();
         }
         /**
          * @hide
diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java
new file mode 100644
index 0000000..92d6f75
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbConfiguration.java
@@ -0,0 +1,178 @@
+/*
+ * 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.usb;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class representing a configuration on a {@link UsbDevice}.
+ * A USB configuration can have one or more interfaces, each one providing a different
+ * piece of functionality, separate from the other interfaces.
+ * An interface will have one or more {@link UsbEndpoint}s, which are the
+ * channels by which the host transfers data with the device.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about communicating with USB hardware, read the
+ * <a href="{@docRoot}guide/topics/usb/index.html">USB</a> developer guide.</p>
+ * </div>
+ */
+public class UsbConfiguration implements Parcelable {
+
+    private final int mId;
+    private final String mName;
+    private final int mAttributes;
+    private final int mMaxPower;
+    private Parcelable[] mInterfaces;
+
+    /**
+     * Mask for "self-powered" bit in the configuration's attributes.
+     * @see #getAttributes
+     */
+    public static final int ATTR_SELF_POWERED_MASK = 1 << 6;
+
+    /**
+     * Mask for "remote wakeup" bit in the configuration's attributes.
+     * @see #getAttributes
+     */
+    public static final int ATTR_REMOTE_WAKEUP_MASK = 1 << 5;
+
+    /**
+     * UsbConfiguration should only be instantiated by UsbService implementation
+     * @hide
+     */
+    public UsbConfiguration(int id, String name, int attributes, int maxPower) {
+        mId = id;
+        mName = name;
+        mAttributes = attributes;
+        mMaxPower = maxPower;
+    }
+
+    /**
+     * Returns the configuration's ID field.
+     * This is an integer that uniquely identifies the configuration on the device.
+     *
+     * @return the configuration's ID
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the configuration's name.
+     *
+     * @return the configuration's name
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Returns the configuration's attributes field.
+     * This field contains a bit field with the following flags:
+     *
+     * Bit 7: always set to 1
+     * Bit 6: self-powered
+     * Bit 5: remote wakeup enabled
+     * Bit 0-4: reserved
+     * @see #ATTR_SELF_POWERED_MASK
+     * @see #ATTR_REMOTE_WAKEUP_MASK
+     * @return the configuration's attributes
+     */
+    public int getAttributes() {
+        return mAttributes;
+    }
+
+    /**
+     * Returns the configuration's max power consumption, in milliamps.
+     *
+     * @return the configuration's max power
+     */
+    public int getMaxPower() {
+        return mMaxPower * 2;
+    }
+
+    /**
+     * Returns the number of {@link UsbInterface}s this configuration contains.
+     *
+     * @return the number of endpoints
+     */
+    public int getInterfaceCount() {
+        return mInterfaces.length;
+    }
+
+    /**
+     * Returns the {@link UsbInterface} at the given index.
+     *
+     * @return the interface
+     */
+    public UsbInterface getInterface(int index) {
+        return (UsbInterface)mInterfaces[index];
+    }
+
+    /**
+     * Only used by UsbService implementation
+     * @hide
+     */
+    public void setInterfaces(Parcelable[] interfaces) {
+        mInterfaces = interfaces;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder("UsbConfiguration[mId=" + mId +
+                ",mName=" + mName + ",mAttributes=" + mAttributes +
+                ",mMaxPower=" + mMaxPower + ",mInterfaces=[");
+        for (int i = 0; i < mInterfaces.length; i++) {
+            builder.append("\n");
+            builder.append(mInterfaces[i].toString());
+        }
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public static final Parcelable.Creator<UsbConfiguration> CREATOR =
+        new Parcelable.Creator<UsbConfiguration>() {
+        public UsbConfiguration createFromParcel(Parcel in) {
+            int id = in.readInt();
+            String name = in.readString();
+            int attributes = in.readInt();
+            int maxPower = in.readInt();
+            Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader());
+            UsbConfiguration configuration = new UsbConfiguration(id, name, attributes, maxPower);
+            configuration.setInterfaces(interfaces);
+            return configuration;
+        }
+
+        public UsbConfiguration[] newArray(int size) {
+            return new UsbConfiguration[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mId);
+        parcel.writeString(mName);
+        parcel.writeInt(mAttributes);
+        parcel.writeInt(mMaxPower);
+        parcel.writeParcelableArray(mInterfaces, 0);
+   }
+}
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index b0ba9c1..d90e06e 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -50,7 +50,10 @@
     private final int mClass;
     private final int mSubclass;
     private final int mProtocol;
-    private final Parcelable[] mInterfaces;
+    private Parcelable[] mConfigurations;
+
+    // list of all interfaces on the device
+    private UsbInterface[] mInterfaces;
 
     /**
      * UsbDevice should only be instantiated by UsbService implementation
@@ -58,8 +61,7 @@
      */
     public UsbDevice(String name, int vendorId, int productId,
             int Class, int subClass, int protocol,
-            String manufacturerName, String productName, String serialNumber,
-            Parcelable[] interfaces) {
+            String manufacturerName, String productName, String serialNumber) {
         mName = name;
         mVendorId = vendorId;
         mProductId = productId;
@@ -69,7 +71,6 @@
         mManufacturerName = manufacturerName;
         mProductName = productName;
         mSerialNumber = serialNumber;
-        mInterfaces = interfaces;
     }
 
     /**
@@ -169,21 +170,74 @@
     }
 
     /**
+     * Returns the number of {@link UsbConfiguration}s this device contains.
+     *
+     * @return the number of configurations
+     */
+    public int getConfigurationCount() {
+        return mConfigurations.length;
+    }
+
+    /**
+     * Returns the {@link UsbConfiguration} at the given index.
+     *
+     * @return the configuration
+     */
+    public UsbConfiguration getConfiguration(int index) {
+        return (UsbConfiguration)mConfigurations[index];
+    }
+
+    private UsbInterface[] getInterfaceList() {
+        if (mInterfaces == null) {
+            int configurationCount = mConfigurations.length;
+            int interfaceCount = 0;
+            for (int i = 0; i < configurationCount; i++) {
+                UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i];
+                interfaceCount += configuration.getInterfaceCount();
+            }
+
+            mInterfaces = new UsbInterface[interfaceCount];
+            int offset = 0;
+            for (int i = 0; i < configurationCount; i++) {
+                UsbConfiguration configuration = (UsbConfiguration)mConfigurations[i];
+                interfaceCount = configuration.getInterfaceCount();
+                for (int j = 0; j < interfaceCount; j++) {
+                    mInterfaces[offset++] = configuration.getInterface(j);
+                }
+            }
+        }
+
+        return mInterfaces;
+    }
+
+    /**
      * Returns the number of {@link UsbInterface}s this device contains.
+     * For devices with multiple configurations, you will probably want to use
+     * {@link UsbConfiguration#getInterfaceCount} instead.
      *
      * @return the number of interfaces
      */
     public int getInterfaceCount() {
-        return mInterfaces.length;
+        return getInterfaceList().length;
     }
 
     /**
      * Returns the {@link UsbInterface} at the given index.
+     * For devices with multiple configurations, you will probably want to use
+     * {@link UsbConfiguration#getInterface} instead.
      *
      * @return the interface
      */
     public UsbInterface getInterface(int index) {
-        return (UsbInterface)mInterfaces[index];
+        return getInterfaceList()[index];
+    }
+
+    /**
+     * Only used by UsbService implementation
+     * @hide
+     */
+    public void setConfigurations(Parcelable[] configuration) {
+        mConfigurations = configuration;
     }
 
     @Override
@@ -204,11 +258,17 @@
 
     @Override
     public String toString() {
-        return "UsbDevice[mName=" + mName + ",mVendorId=" + mVendorId +
-                ",mProductId=" + mProductId + ",mClass=" + mClass +
-                ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
+        StringBuilder builder = new StringBuilder("UsbDevice[mName=" + mName +
+                ",mVendorId=" + mVendorId + ",mProductId=" + mProductId +
+                ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
                 ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName +
-                ",mSerialNumber=" + mSerialNumber + ",mInterfaces=" + mInterfaces + "]";
+                ",mSerialNumber=" + mSerialNumber + ",mConfigurations=[");
+        for (int i = 0; i < mConfigurations.length; i++) {
+            builder.append("\n");
+            builder.append(mConfigurations[i].toString());
+        }
+        builder.append("]");
+        return builder.toString();
     }
 
     public static final Parcelable.Creator<UsbDevice> CREATOR =
@@ -223,9 +283,11 @@
             String manufacturerName = in.readString();
             String productName = in.readString();
             String serialNumber = in.readString();
-            Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader());
-            return new UsbDevice(name, vendorId, productId, clasz, subClass, protocol,
-                                 manufacturerName, productName, serialNumber, interfaces);
+            Parcelable[] configurations = in.readParcelableArray(UsbInterface.class.getClassLoader());
+            UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol,
+                                 manufacturerName, productName, serialNumber);
+            device.setConfigurations(configurations);
+            return device;
         }
 
         public UsbDevice[] newArray(int size) {
@@ -247,7 +309,7 @@
         parcel.writeString(mManufacturerName);
         parcel.writeString(mProductName);
         parcel.writeString(mSerialNumber);
-        parcel.writeParcelableArray(mInterfaces, 0);
+        parcel.writeParcelableArray(mConfigurations, 0);
    }
 
     public static int getDeviceId(String name) {
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 389475f..6283951 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -101,6 +101,25 @@
     }
 
     /**
+     * Sets the current {@link android.hardware.usb.UsbInterface}.
+     * Used to select between two interfaces with the same ID but different alternate setting.
+     *
+     * @return true if the interface was successfully released
+     */
+    public boolean setInterface(UsbInterface intf) {
+        return native_set_interface(intf.getId(), intf.getAlternateSetting());
+    }
+
+    /**
+     * Sets the device's current {@link android.hardware.usb.UsbConfiguration}.
+     *
+     * @return true if the configuration was successfully set
+     */
+    public boolean setConfiguration(UsbConfiguration configuration) {
+        return native_set_configuration(configuration.getId());
+    }
+
+    /**
      * Performs a control transaction on endpoint zero for this device.
      * The direction of the transfer is determined by the request type.
      * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
@@ -236,6 +255,8 @@
     private native byte[] native_get_desc();
     private native boolean native_claim_interface(int interfaceID, boolean force);
     private native boolean native_release_interface(int interfaceID);
+    private native boolean native_set_interface(int interfaceID, int alternateSetting);
+    private native boolean native_set_configuration(int configurationID);
     private native int native_control_request(int requestType, int request, int value,
             int index, byte[] buffer, int offset, int length, int timeout);
     private native int native_bulk_request(int endpoint, byte[] buffer,
diff --git a/core/java/android/hardware/usb/UsbInterface.java b/core/java/android/hardware/usb/UsbInterface.java
index e94baa1..de01a88 100644
--- a/core/java/android/hardware/usb/UsbInterface.java
+++ b/core/java/android/hardware/usb/UsbInterface.java
@@ -35,27 +35,31 @@
 public class UsbInterface implements Parcelable {
 
     private final int mId;
+    private final int mAlternateSetting;
+    private final String mName;
     private final int mClass;
     private final int mSubclass;
     private final int mProtocol;
-    private final Parcelable[] mEndpoints;
+    private Parcelable[] mEndpoints;
 
     /**
      * UsbInterface should only be instantiated by UsbService implementation
      * @hide
      */
-    public UsbInterface(int id, int Class, int subClass, int protocol,
-            Parcelable[] endpoints) {
+    public UsbInterface(int id, int alternateSetting, String name,
+            int Class, int subClass, int protocol) {
         mId = id;
+        mAlternateSetting = alternateSetting;
+        mName = name;
         mClass = Class;
         mSubclass = subClass;
         mProtocol = protocol;
-        mEndpoints = endpoints;
     }
 
     /**
-     * Returns the interface's ID field.
-     * This is an integer that uniquely identifies the interface on the device.
+     * Returns the interface's bInterfaceNumber field.
+     * This is an integer that along with the alternate setting uniquely identifies
+     * the interface on the device.
      *
      * @return the interface's ID
      */
@@ -64,6 +68,28 @@
     }
 
     /**
+     * Returns the interface's bAlternateSetting field.
+     * This is an integer that along with the ID uniquely identifies
+     * the interface on the device.
+     * {@link UsbDeviceConnection#setInterface} can be used to switch between
+     * two interfaces with the same ID but different alternate setting.
+     *
+     * @return the interface's alternate setting
+     */
+    public int getAlternateSetting() {
+        return mAlternateSetting;
+    }
+
+    /**
+     * Returns the interface's name.
+     *
+     * @return the interface's name
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
      * Returns the interface's class field.
      * Some useful constants for USB classes can be found in {@link UsbConstants}
      *
@@ -109,22 +135,42 @@
         return (UsbEndpoint)mEndpoints[index];
     }
 
+    /**
+     * Only used by UsbService implementation
+     * @hide
+     */
+    public void setEndpoints(Parcelable[] endpoints) {
+        mEndpoints = endpoints;
+    }
+
     @Override
     public String toString() {
-        return "UsbInterface[mId=" + mId + ",mClass=" + mClass +
+        StringBuilder builder = new StringBuilder("UsbInterface[mId=" + mId +
+                ",mAlternateSetting=" + mAlternateSetting +
+                ",mName=" + mName + ",mClass=" + mClass +
                 ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
-                ",mEndpoints=" + mEndpoints + "]";
+                ",mEndpoints=[");
+        for (int i = 0; i < mEndpoints.length; i++) {
+            builder.append("\n");
+            builder.append(mEndpoints[i].toString());
+        }
+        builder.append("]");
+        return builder.toString();
     }
 
     public static final Parcelable.Creator<UsbInterface> CREATOR =
         new Parcelable.Creator<UsbInterface>() {
         public UsbInterface createFromParcel(Parcel in) {
             int id = in.readInt();
+            int alternateSetting = in.readInt();
+            String name = in.readString();
             int Class = in.readInt();
             int subClass = in.readInt();
             int protocol = in.readInt();
             Parcelable[] endpoints = in.readParcelableArray(UsbEndpoint.class.getClassLoader());
-            return new UsbInterface(id, Class, subClass, protocol, endpoints);
+            UsbInterface intf = new UsbInterface(id, alternateSetting, name, Class, subClass, protocol);
+            intf.setEndpoints(endpoints);
+            return intf;
         }
 
         public UsbInterface[] newArray(int size) {
@@ -138,6 +184,8 @@
 
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mId);
+        parcel.writeInt(mAlternateSetting);
+        parcel.writeString(mName);
         parcel.writeInt(mClass);
         parcel.writeInt(mSubclass);
         parcel.writeInt(mProtocol);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index e6b9d4c..5b2a29e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -23,9 +23,14 @@
 import android.content.Context;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
+import android.os.IBinder;
+import android.os.INetworkActivityListener;
+import android.os.INetworkManagementService;
 import android.os.Messenger;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.provider.Settings;
+import android.util.ArrayMap;
 
 import java.net.InetAddress;
 
@@ -76,7 +81,7 @@
 
     /**
      * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any
-     * applicable {@link Settings.Secure#CONNECTIVITY_CHANGE_DELAY}.
+     * applicable {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}.
      *
      * @hide
      */
@@ -402,6 +407,8 @@
 
     private final String mPackageName;
 
+    private INetworkManagementService mNMService;
+
     /**
      * Tests if a given integer represents a valid network type.
      * @param networkType the type to be tested
@@ -907,6 +914,92 @@
     }
 
     /**
+     * Callback for use with {@link ConnectivityManager#registerNetworkActiveListener} to
+     * find out when the current network has gone in to a high power state.
+     */
+    public interface OnNetworkActiveListener {
+        /**
+         * Called on the main thread of the process to report that the current data network
+         * has become active, and it is now a good time to perform any pending network
+         * operations.  Note that this listener only tells you when the network becomes
+         * active; if at any other time you want to know whether it is active (and thus okay
+         * to initiate network traffic), you can retrieve its instantaneous state with
+         * {@link ConnectivityManager#isNetworkActive}.
+         */
+        public void onNetworkActive();
+    }
+
+    private INetworkManagementService getNetworkManagementService() {
+        synchronized (this) {
+            if (mNMService != null) {
+                return mNMService;
+            }
+            IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+            mNMService = INetworkManagementService.Stub.asInterface(b);
+            return mNMService;
+        }
+    }
+
+    private final ArrayMap<OnNetworkActiveListener, INetworkActivityListener>
+            mNetworkActivityListeners
+                    = new ArrayMap<OnNetworkActiveListener, INetworkActivityListener>();
+
+    /**
+     * Start listening to reports when the data network is active, meaning it is
+     * a good time to perform network traffic.  Use {@link #isNetworkActive()}
+     * to determine the current state of the network after registering the listener.
+     *
+     * @param l The listener to be told when the network is active.
+     */
+    public void registerNetworkActiveListener(final OnNetworkActiveListener l) {
+        INetworkActivityListener rl = new INetworkActivityListener.Stub() {
+            @Override
+            public void onNetworkActive() throws RemoteException {
+                l.onNetworkActive();
+            }
+        };
+
+        try {
+            getNetworkManagementService().registerNetworkActivityListener(rl);
+            mNetworkActivityListeners.put(l, rl);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Remove network active listener previously registered with
+     * {@link #registerNetworkActiveListener}.
+     *
+     * @param l Previously registered listener.
+     */
+    public void unregisterNetworkActiveListener(OnNetworkActiveListener l) {
+        INetworkActivityListener rl = mNetworkActivityListeners.get(l);
+        if (rl == null) {
+            throw new IllegalArgumentException("Listener not registered: " + l);
+        }
+        try {
+            getNetworkManagementService().unregisterNetworkActivityListener(rl);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Return whether the data network is currently active.  An active network means that
+     * it is currently in a high power state for performing data transmission.  On some
+     * types of networks, it may be expensive to move and stay in such a state, so it is
+     * more power efficient to batch network traffic together when the radio is already in
+     * this state.  This method tells you whether right now is currently a good time to
+     * initiate network traffic, as the network is already active.
+     */
+    public boolean isNetworkActive() {
+        try {
+            return getNetworkManagementService().isNetworkActive();
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
      * {@hide}
      */
     public ConnectivityManager(IConnectivityManager service, String packageName) {
@@ -1021,7 +1114,7 @@
 
     /**
      * Check if the device allows for tethering.  It may be disabled via
-     * {@code ro.tether.denied} system property, {@link Settings#TETHER_SUPPORTED} or
+     * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or
      * due to device configuration.
      *
      * @return a boolean - {@code true} indicating Tethering is supported.
@@ -1209,7 +1302,7 @@
      * doing something unusual like general internal filtering this may be useful.  On
      * a private network where the proxy is not accessible, you may break HTTP using this.
      *
-     * @param proxyProperties The a {@link ProxyProperites} object defining the new global
+     * @param p The a {@link ProxyProperties} object defining the new global
      *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
      *
      * <p>This method requires the call to hold the permission
@@ -1362,7 +1455,7 @@
     /**
      * Supply the backend messenger for a network tracker
      *
-     * @param type NetworkType to set
+     * @param networkType NetworkType to set
      * @param messenger {@link Messenger}
      * {@hide}
      */
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 25514f4..54d43d3 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -507,6 +507,17 @@
     }
 
     /**
+     * Fast path for battery stats.
+     */
+    public long getTotalPackets() {
+        long total = 0;
+        for (int i = size-1; i >= 0; i--) {
+            total += rxPackets[i] + txPackets[i];
+        }
+        return total;
+    }
+
+    /**
      * Subtract the given {@link NetworkStats}, effectively leaving the delta
      * between two snapshots in time. Assumes that statistics rows collect over
      * time, and that none of them have disappeared.
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index d7dc7f5..7385dff 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -151,9 +151,10 @@
     }
 
     /**
-     * Protect a socket from VPN connections. The socket will be bound to the
-     * current default network interface, so its traffic will not be forwarded
-     * through VPN. This method is useful if some connections need to be kept
+     * Protect a socket from VPN connections. After protecting, data sent
+     * through this socket will go directly to the underlying network,
+     * so its traffic will not be forwarded through the VPN.
+     * This method is useful if some connections need to be kept
      * outside of VPN. For example, a VPN tunnel should protect itself if its
      * destination is covered by VPN routes. Otherwise its outgoing packets
      * will be sent back to the VPN interface and cause an infinite loop. This
diff --git a/core/java/android/os/BatteryProperties.java b/core/java/android/os/BatteryProperties.java
index 2d67264..8f5cf8b 100644
--- a/core/java/android/os/BatteryProperties.java
+++ b/core/java/android/os/BatteryProperties.java
@@ -15,9 +15,6 @@
 
 package android.os;
 
-import android.os.Parcel;
-import android.os.Parcelable;
-
 /**
  * {@hide}
  */
@@ -33,6 +30,22 @@
     public int batteryTemperature;
     public String batteryTechnology;
 
+    public BatteryProperties() {
+    }
+
+    public void set(BatteryProperties other) {
+        chargerAcOnline = other.chargerAcOnline;
+        chargerUsbOnline = other.chargerUsbOnline;
+        chargerWirelessOnline = other.chargerWirelessOnline;
+        batteryStatus = other.batteryStatus;
+        batteryHealth = other.batteryHealth;
+        batteryPresent = other.batteryPresent;
+        batteryLevel = other.batteryLevel;
+        batteryVoltage = other.batteryVoltage;
+        batteryTemperature = other.batteryTemperature;
+        batteryTechnology = other.batteryTechnology;
+    }
+
     /*
      * Parcel read/write code must be kept in sync with
      * frameworks/native/services/batteryservice/BatteryProperties.cpp
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index dfba208..a965e00 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -326,6 +326,8 @@
         public abstract boolean hasNetworkActivity();
         public abstract long getNetworkActivityBytes(int type, int which);
         public abstract long getNetworkActivityPackets(int type, int which);
+        public abstract long getMobileRadioActiveTime(int which);
+        public abstract int getMobileRadioActiveCount(int which);
 
         public static abstract class Sensor {
             /*
@@ -588,8 +590,10 @@
         public static final int EVENT_FOREGROUND = 0x0002;
         // Event is about an application package that is at the top of the screen.
         public static final int EVENT_TOP = 0x0003;
+        // Event is about an application package that is at the top of the screen.
+        public static final int EVENT_SYNC = 0x0004;
         // Number of event types.
-        public static final int EVENT_COUNT = 0x0004;
+        public static final int EVENT_COUNT = 0x0005;
 
         public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START;
         public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH;
@@ -597,6 +601,8 @@
         public static final int EVENT_FOREGROUND_FINISH = EVENT_FOREGROUND | EVENT_FLAG_FINISH;
         public static final int EVENT_TOP_START = EVENT_TOP | EVENT_FLAG_START;
         public static final int EVENT_TOP_FINISH = EVENT_TOP | EVENT_FLAG_FINISH;
+        public static final int EVENT_SYNC_START = EVENT_SYNC | EVENT_FLAG_START;
+        public static final int EVENT_SYNC_FINISH = EVENT_SYNC | EVENT_FLAG_FINISH;
 
         // For CMD_EVENT.
         public int eventCode;
@@ -827,6 +833,13 @@
      */
     public abstract long getScreenOnTime(long batteryRealtime, int which);
     
+    /**
+     * Returns the number of times the screen was turned on.
+     *
+     * {@hide}
+     */
+    public abstract int getScreenOnCount(int which);
+
     public static final int SCREEN_BRIGHTNESS_DARK = 0;
     public static final int SCREEN_BRIGHTNESS_DIM = 1;
     public static final int SCREEN_BRIGHTNESS_MEDIUM = 2;
@@ -863,6 +876,13 @@
     public abstract long getPhoneOnTime(long batteryRealtime, int which);
     
     /**
+     * Returns the number of times a phone call was activated.
+     *
+     * {@hide}
+     */
+    public abstract int getPhoneOnCount(int which);
+
+    /**
      * Returns the time in microseconds that the phone has been running with
      * the given signal strength.
      * 
@@ -895,6 +915,28 @@
      */
     public abstract long getMobileRadioActiveTime(long batteryRealtime, int which);
 
+    /**
+     * Returns the number of times that the mobile network has transitioned to the
+     * active state.
+     *
+     * {@hide}
+     */
+    public abstract int getMobileRadioActiveCount(int which);
+
+    /**
+     * Returns the time in microseconds that the mobile network has been active
+     * (in a high power state) but not being able to blame on an app.
+     *
+     * {@hide}
+     */
+    public abstract long getMobileRadioActiveUnknownTime(int which);
+
+    /**
+     * Return count of number of times radio was up that could not be blamed on apps.
+     *
+     * {@hide}
+     */
+    public abstract int getMobileRadioActiveUnknownCount(int which);
 
     public static final int DATA_CONNECTION_NONE = 0;
     public static final int DATA_CONNECTION_GPRS = 1;
@@ -975,11 +1017,11 @@
     };
 
     public static final String[] HISTORY_EVENT_NAMES = new String[] {
-            "null", "proc", "fg", "top"
+            "null", "proc", "fg", "top", "sync"
     };
 
     public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
-            "Nl", "Pr", "Fg", "Tp"
+            "Enl", "Epr", "Efg", "Etp", "Esy"
     };
 
     /**
@@ -1234,6 +1276,13 @@
         sb.append("ms ");
     }
 
+    private final static void formatTimeMsNoSpace(StringBuilder sb, long time) {
+        long sec = time / 1000;
+        formatTimeRaw(sb, sec);
+        sb.append(time - (sec * 1000));
+        sb.append("ms");
+    }
+
     private final String formatRatioLocked(long num, long den) {
         if (den == 0L) {
             return "--%";
@@ -1586,6 +1635,8 @@
             long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
             long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
             long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+            long mobileActiveTime = u.getMobileRadioActiveTime(which);
+            int mobileActiveCount = u.getMobileRadioActiveCount(which);
             long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
             long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
@@ -1594,11 +1645,12 @@
 
             if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
                     || mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0
-                    || wifiPacketsTx > 0) {
+                    || wifiPacketsTx > 0 || mobileActiveTime > 0 || mobileActiveCount > 0) {
                 dumpLine(pw, uid, category, NETWORK_DATA, mobileBytesRx, mobileBytesTx,
                         wifiBytesRx, wifiBytesTx,
                         mobilePacketsRx, mobilePacketsTx,
-                        wifiPacketsRx, wifiPacketsTx);
+                        wifiPacketsRx, wifiPacketsTx,
+                        mobileActiveTime, mobileActiveCount);
             }
 
             if (fullWifiLockOnTime != 0 || wifiScanTime != 0
@@ -1782,7 +1834,7 @@
                 formatTimeMs(sb, totalRealtime / 1000);
                 sb.append("realtime, ");
                 formatTimeMs(sb, totalUptime / 1000);
-                sb.append("uptime, ");
+                sb.append("uptime");
         pw.println(sb.toString());
         pw.print("  Start clock time: ");
         pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
@@ -1796,21 +1848,27 @@
         sb.append(prefix);
                 sb.append("  Screen on: "); formatTimeMs(sb, screenOnTime / 1000);
                 sb.append("("); sb.append(formatRatioLocked(screenOnTime, whichBatteryRealtime));
-                sb.append("), Input events: "); sb.append(getInputEventCount(which));
-                sb.append(", Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
-                sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
-                sb.append(")");
+                sb.append(") "); sb.append(getScreenOnCount(which));
+                sb.append("x, Input events: "); sb.append(getInputEventCount(which));
         pw.println(sb.toString());
+        if (phoneOnTime != 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("  Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
+                    sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
+                    sb.append(") "); sb.append(getPhoneOnCount(which));
+        }
         sb.setLength(0);
         sb.append(prefix);
-        sb.append("  Screen brightnesses: ");
+        sb.append("  Screen brightnesses:");
         boolean didOne = false;
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             final long time = getScreenBrightnessTime(i, batteryRealtime, which);
             if (time == 0) {
                 continue;
             }
-            if (didOne) sb.append(", ");
+            sb.append("\n    ");
+            sb.append(prefix);
             didOne = true;
             sb.append(SCREEN_BRIGHTNESS_NAMES[i]);
             sb.append(" ");
@@ -1819,7 +1877,7 @@
             sb.append(formatRatioLocked(time, screenOnTime));
             sb.append(")");
         }
-        if (!didOne) sb.append("No activity");
+        if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
         
         // Calculate wakelock times across all uids.
@@ -1916,24 +1974,27 @@
         long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
         long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
 
+        if (fullWakeLockTimeTotalMicros != 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("  Total full wakelock time: "); formatTimeMsNoSpace(sb,
+                            (fullWakeLockTimeTotalMicros + 500) / 1000);
+            pw.println(sb.toString());
+        }
+
+        if (partialWakeLockTimeTotalMicros != 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("  Total partial wakelock time: "); formatTimeMsNoSpace(sb,
+                            (partialWakeLockTimeTotalMicros + 500) / 1000);
+            pw.println(sb.toString());
+        }
+
         pw.print(prefix);
                 pw.print("  Mobile total received: "); pw.print(formatBytesLocked(mobileRxTotalBytes));
                 pw.print(", sent: "); pw.print(formatBytesLocked(mobileTxTotalBytes));
                 pw.print(" (packets received "); pw.print(mobileRxTotalPackets);
                 pw.print(", sent "); pw.print(mobileTxTotalPackets); pw.println(")");
-        pw.print(prefix);
-                pw.print("  Wi-Fi total received: "); pw.print(formatBytesLocked(wifiRxTotalBytes));
-                pw.print(", sent: "); pw.print(formatBytesLocked(wifiTxTotalBytes));
-                pw.print(" (packets received "); pw.print(wifiRxTotalPackets);
-                pw.print(", sent "); pw.print(wifiTxTotalPackets); pw.println(")");
-        sb.setLength(0);
-        sb.append(prefix);
-                sb.append("  Total full wakelock time: "); formatTimeMs(sb,
-                        (fullWakeLockTimeTotalMicros + 500) / 1000);
-                sb.append(", Total partial wakelock time: "); formatTimeMs(sb,
-                        (partialWakeLockTimeTotalMicros + 500) / 1000);
-        pw.println(sb.toString());
-        
         sb.setLength(0);
         sb.append(prefix);
         sb.append("  Signal levels:");
@@ -1944,6 +2005,7 @@
                 continue;
             }
             sb.append("\n    ");
+            sb.append(prefix);
             didOne = true;
             sb.append(SignalStrength.SIGNAL_STRENGTH_NAMES[i]);
             sb.append(" ");
@@ -1960,7 +2022,7 @@
         sb.setLength(0);
         sb.append(prefix);
         sb.append("  Signal scanning time: ");
-        formatTimeMs(sb, getPhoneSignalScanningTime(batteryRealtime, which) / 1000);
+        formatTimeMsNoSpace(sb, getPhoneSignalScanningTime(batteryRealtime, which) / 1000);
         pw.println(sb.toString());
 
         sb.setLength(0);
@@ -1973,6 +2035,7 @@
                 continue;
             }
             sb.append("\n    ");
+            sb.append(prefix);
             didOne = true;
             sb.append(DATA_CONNECTION_NAMES[i]);
             sb.append(" ");
@@ -1989,9 +2052,31 @@
         sb.setLength(0);
         sb.append(prefix);
         sb.append("  Mobile radio active time: ");
-        formatTimeMs(sb, getMobileRadioActiveTime(batteryRealtime, which) / 1000);
+        final long mobileActiveTime = getMobileRadioActiveTime(batteryRealtime, which);
+        formatTimeMs(sb, mobileActiveTime / 1000);
+        sb.append("("); sb.append(formatRatioLocked(mobileActiveTime, whichBatteryRealtime));
+        sb.append(") "); sb.append(getMobileRadioActiveCount(which));
+        sb.append("x");
         pw.println(sb.toString());
 
+        final long mobileActiveUnknownTime = getMobileRadioActiveUnknownTime(which);
+        if (mobileActiveUnknownTime != 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+            sb.append("  Mobile radio active unknown time: ");
+            formatTimeMs(sb, mobileActiveUnknownTime / 1000);
+            sb.append("(");
+            sb.append(formatRatioLocked(mobileActiveUnknownTime, whichBatteryRealtime));
+            sb.append(") "); sb.append(getMobileRadioActiveUnknownCount(which));
+            sb.append("x");
+            pw.println(sb.toString());
+        }
+
+        pw.print(prefix);
+                pw.print("  Wi-Fi total received: "); pw.print(formatBytesLocked(wifiRxTotalBytes));
+                pw.print(", sent: "); pw.print(formatBytesLocked(wifiTxTotalBytes));
+                pw.print(" (packets received "); pw.print(wifiRxTotalPackets);
+                pw.print(", sent "); pw.print(wifiTxTotalPackets); pw.println(")");
         sb.setLength(0);
         sb.append(prefix);
                 sb.append("  Wifi on: "); formatTimeMs(sb, wifiOnTime / 1000);
@@ -2128,7 +2213,8 @@
                         pw.println();
                         break;
                     case APP:
-                        pw.print(prefix); pw.print("    Uid "); pw.print(bs.uidObj.getUid());
+                        pw.print(prefix); pw.print("    Uid ");
+                        UserHandle.formatUid(pw, bs.uidObj.getUid());
                         pw.print(": "); printmAh(pw, bs.value); pw.println();
                         break;
                     case USER:
@@ -2148,6 +2234,32 @@
             pw.println();
         }
 
+        sippers = helper.getMobilemsppList();
+        if (sippers != null && sippers.size() > 0) {
+            pw.print(prefix); pw.println("  Per-app mobile ms per packet:");
+            long totalTime = 0;
+            for (int i=0; i<sippers.size(); i++) {
+                BatterySipper bs = sippers.get(i);
+                sb.setLength(0);
+                sb.append(prefix); sb.append("    Uid ");
+                UserHandle.formatUid(sb, bs.uidObj.getUid());
+                sb.append(": "); sb.append(BatteryStatsHelper.makemAh(bs.mobilemspp));
+                sb.append(" ("); sb.append(bs.mobileRxPackets+bs.mobileTxPackets);
+                sb.append(" packets over "); formatTimeMsNoSpace(sb, bs.mobileActive);
+                sb.append(") "); sb.append(bs.mobileActiveCount); sb.append("x");
+                pw.println(sb.toString());
+                totalTime += bs.mobileActive;
+            }
+            sb.setLength(0);
+            sb.append(prefix);
+            sb.append("    TOTAL TIME: ");
+            formatTimeMs(sb, totalTime);
+            sb.append("("); sb.append(formatRatioLocked(totalTime, whichBatteryRealtime));
+            sb.append(")");
+            pw.println(sb.toString());
+            pw.println();
+        }
+
         if (timers.size() > 0) {
             Collections.sort(timers, timerComparator);
             pw.print(prefix); pw.println("  All partial wake locks:");
@@ -2179,13 +2291,15 @@
             UserHandle.formatUid(pw, uid);
             pw.println(":");
             boolean uidActivity = false;
-            
+
             long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
             long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
             long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
             long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
             long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
             long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+            long uidMobileActiveTime = u.getMobileRadioActiveTime(which);
+            int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
             long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
             long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
@@ -2200,6 +2314,23 @@
                         pw.print(" sent (packets "); pw.print(mobileRxPackets);
                         pw.print(" received, "); pw.print(mobileTxPackets); pw.println(" sent)");
             }
+            if (uidMobileActiveTime > 0 || uidMobileActiveCount > 0) {
+                sb.setLength(0);
+                sb.append(prefix); sb.append("    Mobile radio active: ");
+                formatTimeMs(sb, uidMobileActiveTime / 1000);
+                sb.append("(");
+                sb.append(formatRatioLocked(uidMobileActiveTime, mobileActiveTime));
+                sb.append(") "); sb.append(uidMobileActiveCount); sb.append("x");
+                long packets = mobileRxPackets + mobileTxPackets;
+                if (packets == 0) {
+                    packets = 1;
+                }
+                sb.append(" @ ");
+                sb.append(BatteryStatsHelper.makemAh(uidMobileActiveTime / 1000 / (double)packets));
+                sb.append(" mspp");
+                pw.println(sb.toString());
+            }
+
             if (wifiRxBytes > 0 || wifiTxBytes > 0 || wifiRxPackets > 0 || wifiTxPackets > 0) {
                 pw.print(prefix); pw.print("    Wi-Fi network: ");
                         pw.print(formatBytesLocked(wifiRxBytes)); pw.print(" received, ");
@@ -2208,6 +2339,24 @@
                         pw.print(" received, "); pw.print(wifiTxPackets); pw.println(" sent)");
             }
 
+            if (fullWifiLockOnTime != 0 || wifiScanTime != 0
+                    || uidWifiRunningTime != 0) {
+                sb.setLength(0);
+                sb.append(prefix); sb.append("    Wifi Running: ");
+                        formatTimeMs(sb, uidWifiRunningTime / 1000);
+                        sb.append("("); sb.append(formatRatioLocked(uidWifiRunningTime,
+                                whichBatteryRealtime)); sb.append(")\n");
+                sb.append(prefix); sb.append("    Full Wifi Lock: "); 
+                        formatTimeMs(sb, fullWifiLockOnTime / 1000);
+                        sb.append("("); sb.append(formatRatioLocked(fullWifiLockOnTime,
+                                whichBatteryRealtime)); sb.append(")\n");
+                sb.append(prefix); sb.append("    Wifi Scan: ");
+                        formatTimeMs(sb, wifiScanTime / 1000);
+                        sb.append("("); sb.append(formatRatioLocked(wifiScanTime,
+                                whichBatteryRealtime)); sb.append(")");
+                pw.println(sb.toString());
+            }
+
             if (u.hasUserActivity()) {
                 boolean hasData = false;
                 for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
@@ -2229,24 +2378,6 @@
                     pw.println(sb.toString());
                 }
             }
-            
-            if (fullWifiLockOnTime != 0 || wifiScanTime != 0
-                    || uidWifiRunningTime != 0) {
-                sb.setLength(0);
-                sb.append(prefix); sb.append("    Wifi Running: ");
-                        formatTimeMs(sb, uidWifiRunningTime / 1000);
-                        sb.append("("); sb.append(formatRatioLocked(uidWifiRunningTime,
-                                whichBatteryRealtime)); sb.append(")\n");
-                sb.append(prefix); sb.append("    Full Wifi Lock: "); 
-                        formatTimeMs(sb, fullWifiLockOnTime / 1000);
-                        sb.append("("); sb.append(formatRatioLocked(fullWifiLockOnTime,
-                                whichBatteryRealtime)); sb.append(")\n");
-                sb.append(prefix); sb.append("    Wifi Scan: ");
-                        formatTimeMs(sb, wifiScanTime / 1000);
-                        sb.append("("); sb.append(formatRatioLocked(wifiScanTime,
-                                whichBatteryRealtime)); sb.append(")");
-                pw.println(sb.toString());
-            }
 
             Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
             if (wakelocks.size() > 0) {
diff --git a/media/java/android/media/MediaSessionToken.aidl b/core/java/android/os/INetworkActivityListener.aidl
similarity index 76%
copy from media/java/android/media/MediaSessionToken.aidl
copy to core/java/android/os/INetworkActivityListener.aidl
index e2f1abc..24e6e55 100644
--- a/media/java/android/media/MediaSessionToken.aidl
+++ b/core/java/android/os/INetworkActivityListener.aidl
@@ -1,4 +1,4 @@
-/* Copyright 2014, The Android Open Source Project
+/* Copyright 2013, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
@@ -13,6 +13,12 @@
 ** limitations under the License.
 */
 
-package android.media;
+package android.os;
 
-parcelable MediaSessionToken;
+/**
+ * @hide
+ */
+oneway interface INetworkActivityListener
+{
+    void onNetworkActive();
+}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 21b8ae5..e6a4c5a 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -23,6 +23,7 @@
 import android.net.NetworkStats;
 import android.net.RouteInfo;
 import android.net.wifi.WifiConfiguration;
+import android.os.INetworkActivityListener;
 
 /**
  * @hide
@@ -306,14 +307,12 @@
      * reference-counting if an idletimer already exists for given
      * {@code iface}.
      *
-     * {@code label} usually represents the network type of {@code iface}.
-     * Caller should ensure that {@code label} for an {@code iface} remains the
-     * same for all calls to addIdleTimer.
+     * {@code type} is the type of the interface, such as TYPE_MOBILE.
      *
      * Every {@code addIdleTimer} should be paired with a
      * {@link removeIdleTimer} to cleanup when the network disconnects.
      */
-    void addIdleTimer(String iface, int timeout, String label);
+    void addIdleTimer(String iface, int timeout, int type);
 
     /**
      * Removes idletimer for an interface.
@@ -441,4 +440,19 @@
      * Determine whether the clatd (464xlat) service has been started
      */
     boolean isClatdStarted();
+
+    /**
+     * Start listening for mobile activity state changes.
+     */
+    void registerNetworkActivityListener(INetworkActivityListener listener);
+
+    /**
+     * Stop listening for mobile activity state changes.
+     */
+    void unregisterNetworkActivityListener(INetworkActivityListener listener);
+
+    /**
+     * Check whether the mobile radio is currently active.
+     */
+    boolean isNetworkActive();
 }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 56176a4..069285a 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -25,8 +25,10 @@
 {
     // WARNING: The first four methods must remain the first three methods because their
     // transaction numbers must not change unless IPowerManager.cpp is also updated.
-    void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws);
-    void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName, int uidtoblame);
+    void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws,
+            String historyTag);
+    void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName,
+            int uidtoblame);
     void releaseWakeLock(IBinder lock, int flags);
     void updateWakeLockUids(IBinder lock, in int[] uids);
 
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 4d4c337..74ca3bb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -662,6 +662,7 @@
         private boolean mRefCounted = true;
         private boolean mHeld;
         private WorkSource mWorkSource;
+        private String mHistoryTag;
 
         private final Runnable mReleaser = new Runnable() {
             public void run() {
@@ -748,7 +749,8 @@
                 // been explicitly released by the keyguard.
                 mHandler.removeCallbacks(mReleaser);
                 try {
-                    mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource);
+                    mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
+                            mHistoryTag);
                 } catch (RemoteException e) {
                 }
                 mHeld = true;
@@ -855,6 +857,11 @@
         }
 
         /** @hide */
+        public void setHistoryTag(String tag) {
+            mHistoryTag = tag;
+        }
+
+        /** @hide */
         public void setUnimportantForLogging(boolean state) {
             if (state) mFlags |= UNIMPORTANT_FOR_LOGGING;
             else mFlags &= ~UNIMPORTANT_FOR_LOGGING;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 18018e2..bf0be40 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -749,6 +749,14 @@
     public static final String ACTION_PRINT_SETTINGS =
             "android.settings.ACTION_PRINT_SETTINGS";
 
+    /**
+     * Activity Action: Show Zen Mode configuration settings.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ZEN_MODE_SETTINGS = "android.settings.ZEN_MODE_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -6082,6 +6090,35 @@
                 "lock_screen_show_notifications";
 
         /**
+         * Defines global zen mode.  One of ZEN_MODE_OFF, ZEN_MODE_LIMITED, ZEN_MODE_FULL.
+         *
+         * @hide
+         */
+        public static final String ZEN_MODE = "zen_mode";
+
+        /** @hide */ public static final int ZEN_MODE_OFF = 0;
+        /** @hide */ public static final int ZEN_MODE_LIMITED = 1;
+        /** @hide */ public static final int ZEN_MODE_FULL = 2;
+
+        /** @hide */ public static String zenModeToString(int mode) {
+            if (mode == ZEN_MODE_OFF) return "ZEN_MODE_OFF";
+            if (mode == ZEN_MODE_LIMITED) return "ZEN_MODE_LIMITED";
+            if (mode == ZEN_MODE_FULL) return "ZEN_MODE_FULL";
+            throw new IllegalArgumentException("Invalid zen mode: " + mode);
+        }
+
+        /**
+         * Defines global heads up toggle.  One of HEADS_UP_OFF, HEADS_UP_ON.
+         *
+         * @hide
+         */
+        public static final String HEADS_UP_NOTIFICATIONS_ENABLED =
+                "heads_up_notifications_enabled";
+
+        /** @hide */ public static final int HEADS_UP_OFF = 0;
+        /** @hide */ public static final int HEADS_UP_ON = 1;
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index fd3f9b3..9f1e72d 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -552,8 +552,7 @@
         return false;
     }
 
-    /** @hide */
-    public static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
+    private static ArrayMap<Animator, AnimationInfo> getRunningAnimators() {
         ArrayMap<Animator, AnimationInfo> runningAnimators = sRunningAnimators.get();
         if (runningAnimators == null) {
             runningAnimators = new ArrayMap<Animator, AnimationInfo>();
@@ -1113,30 +1112,32 @@
                 }
             }
         }
-        TransitionValues values = new TransitionValues();
-        values.view = view;
-        if (start) {
-            captureStartValues(values);
-        } else {
-            captureEndValues(values);
-        }
-        if (start) {
-            if (!isListViewItem) {
-                mStartValues.viewValues.put(view, values);
-                if (id >= 0) {
-                    mStartValues.idValues.put((int) id, values);
-                }
+        if (view.getParent() instanceof ViewGroup) {
+            TransitionValues values = new TransitionValues();
+            values.view = view;
+            if (start) {
+                captureStartValues(values);
             } else {
-                mStartValues.itemIdValues.put(itemId, values);
+                captureEndValues(values);
             }
-        } else {
-            if (!isListViewItem) {
-                mEndValues.viewValues.put(view, values);
-                if (id >= 0) {
-                    mEndValues.idValues.put((int) id, values);
+            if (start) {
+                if (!isListViewItem) {
+                    mStartValues.viewValues.put(view, values);
+                    if (id >= 0) {
+                        mStartValues.idValues.put((int) id, values);
+                    }
+                } else {
+                    mStartValues.itemIdValues.put(itemId, values);
                 }
             } else {
-                mEndValues.itemIdValues.put(itemId, values);
+                if (!isListViewItem) {
+                    mEndValues.viewValues.put(view, values);
+                    if (id >= 0) {
+                        mEndValues.idValues.put((int) id, values);
+                    }
+                } else {
+                    mEndValues.itemIdValues.put(itemId, values);
+                }
             }
         }
         if (view instanceof ViewGroup) {
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index 9fa554c..912f2ed 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -285,46 +285,27 @@
                 com.android.internal.R.styleable.TransitionManager);
         int transitionId = a.getResourceId(
                 com.android.internal.R.styleable.TransitionManager_transition, -1);
-        Scene fromScene = null, toScene = null;
         int fromId = a.getResourceId(
                 com.android.internal.R.styleable.TransitionManager_fromScene, -1);
-        if (fromId >= 0) fromScene = Scene.getSceneForLayout(sceneRoot, fromId, mContext);
+        Scene fromScene = (fromId < 0) ? null: Scene.getSceneForLayout(sceneRoot, fromId, mContext);
         int toId = a.getResourceId(
                 com.android.internal.R.styleable.TransitionManager_toScene, -1);
-        if (toId >= 0) toScene = Scene.getSceneForLayout(sceneRoot, toId, mContext);
-        String fromName = a.getString(
-                com.android.internal.R.styleable.TransitionManager_fromSceneName);
-        String toName = a.getString(
-                com.android.internal.R.styleable.TransitionManager_toSceneName);
+        Scene toScene = (toId < 0) ? null : Scene.getSceneForLayout(sceneRoot, toId, mContext);
+
         if (transitionId >= 0) {
             Transition transition = inflateTransition(transitionId);
             if (transition != null) {
-                if (fromScene != null) {
-                    boolean hasDest = false;
-                    if (toScene != null) {
-                        transitionManager.setTransition(fromScene, toScene, transition);
-                        hasDest = true;
-                    }
-
-                    if (!TextUtils.isEmpty(toName)) {
-                        transitionManager.setTransition(fromScene, toName, transition);
-                        hasDest = true;
-                    }
-
-                    if (!hasDest) {
-                        throw new RuntimeException("No matching toScene or toSceneName for given " +
-                                "fromScene for transition ID " + transitionId);
-                    }
-                } else if (toId >= 0) {
-                    transitionManager.setTransition(toScene, transition);
-                }
-                if (fromName != null) {
-                    if (toScene != null) {
-                        transitionManager.setTransition(fromName, toScene, transition);
-                    } else {
-                        throw new RuntimeException("No matching toScene for given fromSceneName " +
+                if (fromScene == null) {
+                    if (toScene == null) {
+                        throw new RuntimeException("No matching fromScene or toScene " +
                                 "for transition ID " + transitionId);
+                    } else {
+                        transitionManager.setTransition(toScene, transition);
                     }
+                } else if (toScene == null) {
+                    transitionManager.setExitTransition(fromScene, transition);
+                } else {
+                    transitionManager.setTransition(fromScene, toScene, transition);
                 }
             }
         }
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 0106f7fb..f3abfb0 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -70,12 +70,9 @@
     private static final String[] EMPTY_STRINGS = new String[0];
 
     ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
+    ArrayMap<Scene, Transition> mExitSceneTransitions = new ArrayMap<Scene, Transition>();
     ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
             new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
-    ArrayMap<Scene, ArrayMap<String, Transition>> mSceneNameTransitions =
-            new ArrayMap<Scene, ArrayMap<String, Transition>>();
-    ArrayMap<String, ArrayMap<Scene, Transition>> mNameSceneTransitions =
-            new ArrayMap<String, ArrayMap<Scene, Transition>>();
     private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
             sRunningTransitions =
             new ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>();
@@ -122,6 +119,21 @@
     }
 
     /**
+     * Sets a specific transition to occur when the given scene is exited. This
+     * has the lowest priority -- if a Scene-to-Scene transition or
+     * Scene enter transition can be applied, it will.
+     *
+     * @param scene The scene which, when exited, will cause the given
+     * transition to run.
+     * @param transition The transition that will play when the given scene is
+     * exited. A value of null will result in the default behavior of
+     * using the default transition instead.
+     */
+    public void setExitTransition(Scene scene, Transition transition) {
+        mExitSceneTransitions.put(scene, transition);
+    }
+
+    /**
      * Sets a specific transition to occur when the given pair of scenes is
      * exited/entered.
      *
@@ -169,6 +181,9 @@
             }
         }
         transition = mSceneTransitions.get(scene);
+        if (transition == null && sceneRoot != null) {
+            transition = mExitSceneTransitions.get(Scene.getCurrentScene(sceneRoot));
+        }
         return (transition != null) ? transition : sDefaultTransition;
     }
 
@@ -224,138 +239,31 @@
     }
 
     /**
-     * Retrieve the transition from a named scene to a target defined scene if one has been
+     * Retrieve the transition to a target defined scene if one has been
      * associated with this TransitionManager.
      *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
-     * @param fromName Named scene that this transition corresponds to
      * @param toScene Target scene that this transition will move to
-     * @return Transition corresponding to the given fromName and toScene or null
+     * @return Transition corresponding to the given toScene or null
      *         if no association exists in this TransitionManager
      *
-     * @see #setTransition(String, Scene, Transition)
+     * @see #setTransition(Scene, Transition)
+     * @hide
      */
-    public Transition getNamedTransition(String fromName, Scene toScene) {
-        ArrayMap<Scene, Transition> m = mNameSceneTransitions.get(fromName);
-        if (m != null) {
-            return m.get(toScene);
-        }
-        return null;
+    public Transition getEnterTransition(Scene toScene) {
+        return mSceneTransitions.get(toScene);
     }
 
     /**
      * Retrieve the transition from a defined scene to a target named scene if one has been
      * associated with this TransitionManager.
      *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
      * @param fromScene Scene that this transition starts from
-     * @param toName Name of the target scene
-     * @return Transition corresponding to the given fromScene and toName or null
+     * @return Transition corresponding to the given fromScene or null
      *         if no association exists in this TransitionManager
+     * @hide
      */
-    public Transition getNamedTransition(Scene fromScene, String toName) {
-        ArrayMap<String, Transition> m = mSceneNameTransitions.get(fromScene);
-        if (m != null) {
-            return m.get(toName);
-        }
-        return null;
-    }
-
-    /**
-     * Retrieve the supported target named scenes when transitioning away from the given scene.
-     *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
-     * @param fromScene Scene to transition from
-     * @return An array of Strings naming each supported transition starting from
-     *         <code>fromScene</code>. If no transitions to a named scene from the given
-     *         scene are supported this function will return a String[] of length 0.
-     *
-     * @see #setTransition(Scene, String, Transition)
-     */
-    public String[] getTargetSceneNames(Scene fromScene) {
-        final ArrayMap<String, Transition> m = mSceneNameTransitions.get(fromScene);
-        if (m == null) {
-            return EMPTY_STRINGS;
-        }
-        final int count = m.size();
-        final String[] result = new String[count];
-        for (int i = 0; i < count; i++) {
-            result[i] = m.keyAt(i);
-        }
-        return result;
-    }
-
-    /**
-     * Set a transition from a specific scene to a named scene.
-     *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
-     * @param fromScene Scene to transition from
-     * @param toName Named scene to transition to
-     * @param transition Transition to use
-     *
-     * @see #getTargetSceneNames(Scene)
-     */
-    public void setTransition(Scene fromScene, String toName, Transition transition) {
-        ArrayMap<String, Transition> m = mSceneNameTransitions.get(fromScene);
-        if (m == null) {
-            m = new ArrayMap<String, Transition>();
-            mSceneNameTransitions.put(fromScene, m);
-        }
-        m.put(toName, transition);
-    }
-
-    /**
-     * Set a transition from a named scene to a concrete scene.
-     *
-     * <p>A named scene is an indirect link for a transition. Fundamentally a named
-     * scene represents a potentially arbitrary intersection point of two otherwise independent
-     * transitions. Activity A may define a transition from scene X to "com.example.scene.FOO"
-     * while activity B may define a transition from scene "com.example.scene.FOO" to scene Y.
-     * In this way applications may define an API for more sophisticated transitions between
-     * caller and called activities very similar to the way that <code>Intent</code> extras
-     * define APIs for arguments and data propagation between activities.</p>
-     *
-     * @param fromName Named scene to transition from
-     * @param toScene Scene to transition to
-     * @param transition Transition to use
-     *
-     * @see #getNamedTransition(String, Scene)
-     */
-    public void setTransition(String fromName, Scene toScene, Transition transition) {
-        ArrayMap<Scene, Transition> m = mNameSceneTransitions.get(fromName);
-        if (m == null) {
-            m = new ArrayMap<Scene, Transition>();
-            mNameSceneTransitions.put(fromName, m);
-        }
-        m.put(toScene, transition);
+    public Transition getExitTransition(Scene fromScene) {
+        return mExitSceneTransitions.get(fromScene);
     }
 
     /**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5a8d2c8..e693b9e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -167,6 +167,13 @@
     public static final int FX_SURFACE_DIM = 0x00020000;
 
     /**
+     * Surface creation flag: Creates a video plane Surface.
+     * This surface is backed by a hardware video plane. It is an error to lock
+     * a video plane surface, since it doesn't have a backing store.
+     */
+    public static final int FX_SURFACE_VIDEO_PLANE = 0x00040000;
+
+    /**
      * Mask used for FX values above.
      *
      */
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 65d3f6d..9b23b35 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -421,7 +421,10 @@
         mWindowType = type;
     }
 
-    private void updateWindow(boolean force, boolean redrawNeeded) {
+    /**
+     * @hide
+     */
+    protected void updateWindow(boolean force, boolean redrawNeeded) {
         if (!mHaveFrame) {
             return;
         }
diff --git a/core/java/android/view/VideoPlaneView.java b/core/java/android/view/VideoPlaneView.java
new file mode 100644
index 0000000..81dcf9d
--- /dev/null
+++ b/core/java/android/view/VideoPlaneView.java
@@ -0,0 +1,53 @@
+/*
+ * 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.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * Provides a dedicated surface embedded inside of a view hierarchy much like a
+ * {@link SurfaceView}, but the surface is actually backed by a hardware video
+ * plane.
+ *
+ * TODO: Eventually this should be separate from SurfaceView.
+ *
+ * @hide
+ */
+public class VideoPlaneView extends SurfaceView {
+    public VideoPlaneView(Context context) {
+        super(context);
+    }
+
+    public VideoPlaneView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public VideoPlaneView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public VideoPlaneView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void updateWindow(boolean force, boolean redrawNeeded) {
+        mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_VIDEO_PLANE;
+        super.updateWindow(force, redrawNeeded);
+    }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e9082c3..99aee29 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -101,7 +101,9 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -18842,6 +18844,33 @@
         }
     }
 
+    /**
+     * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions.
+     * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and
+     *                           a normal View or a ViewGroup with
+     *                           {@link android.view.ViewGroup#isTransitionGroup()} true.
+     * @hide
+     */
+    public void captureTransitioningViews(List<View> transitioningViews) {
+        if (getVisibility() == View.VISIBLE) {
+            transitioningViews.add(this);
+        }
+    }
+
+    /**
+     * Adds all Views that have {@link #getSharedElementName()} non-null to sharedElements.
+     * @param sharedElements Will contain all Views in the hierarchy having a shared element name.
+     * @hide
+     */
+    public void findSharedElements(Map<String, View> sharedElements) {
+        if (getVisibility() == VISIBLE) {
+            String sharedElementName = getSharedElementName();
+            if (sharedElementName != null) {
+                sharedElements.put(sharedElementName, this);
+            }
+        }
+    }
+
     //
     // Properties
     //
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9cd3c9d..cf5e8cf 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -31,6 +31,7 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.util.AttributeSet;
@@ -50,6 +51,8 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
 
@@ -2300,14 +2303,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.
-     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     * is not null or if {@link #getSharedElementName()} 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;
+            return getBackground() != null || getSharedElementName() != null;
         }
     }
 
@@ -2318,7 +2320,6 @@
      *                          in Activity transitions. If false, the ViewGroup won't transition,
      *                          only its children. If true, the entire ViewGroup will transition
      *                          together.
-     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
      */
     public void setTransitionGroup(boolean isTransitionGroup) {
         mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
@@ -5880,6 +5881,37 @@
     protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
     }
 
+    /** @hide */
+    @Override
+    public void captureTransitioningViews(List<View> transitioningViews) {
+        if (getVisibility() != View.VISIBLE) {
+            return;
+        }
+        if (isTransitionGroup()) {
+            transitioningViews.add(this);
+        } else {
+            int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                View child = getChildAt(i);
+                child.captureTransitioningViews(transitioningViews);
+            }
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void findSharedElements(Map<String, View> sharedElements) {
+        if (getVisibility() != VISIBLE) {
+            return;
+        }
+        super.findSharedElements(sharedElements);
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            View child = getChildAt(i);
+            child.findSharedElements(sharedElements);
+        }
+    }
+
     /**
      * LayoutParams are used by views to tell their parents how they want to be
      * laid out. See
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2b32d70..a338e6e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -267,6 +267,10 @@
     HardwareLayer mResizeBuffer;
     long mResizeBufferStartTime;
     int mResizeBufferDuration;
+    // Used to block the creation of the ResizeBuffer due to invalidations in
+    // the previous DisplayList tree that must prevent re-execution.
+    // Currently this means a functor was detached.
+    boolean mBlockResizeBuffer;
     static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
     private ArrayList<LayoutTransition> mPendingTransitions;
 
@@ -667,6 +671,7 @@
     }
 
     public void detachFunctor(int functor) {
+        mBlockResizeBuffer = true;
         if (mAttachInfo.mHardwareRenderer != null) {
             mAttachInfo.mHardwareRenderer.detachFunctor(functor);
         }
@@ -1454,7 +1459,8 @@
                             !mAttachInfo.mTurnOffWindowResizeAnim &&
                             mAttachInfo.mHardwareRenderer != null &&
                             mAttachInfo.mHardwareRenderer.isEnabled() &&
-                            lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
+                            lp != null && !PixelFormat.formatHasAlpha(lp.format)
+                            && !mBlockResizeBuffer) {
 
                         disposeResizeBuffer();
 
@@ -2377,6 +2383,7 @@
                 mCurrentDirty.set(dirty);
                 dirty.setEmpty();
 
+                mBlockResizeBuffer = false;
                 attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
                         animating ? null : mCurrentDirty);
             } else {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 11740ab..24b8248 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -29,9 +29,12 @@
 import android.os.IBinder;
 import android.os.SystemProperties;
 import android.transition.Scene;
+import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.view.accessibility.AccessibilityEvent;
 
+import java.util.Map;
+
 /**
  * Abstract base class for a top-level window look and behavior policy.  An
  * instance of this class should be used as the top-level view added to the
@@ -1386,30 +1389,43 @@
      * @hide
      */
     public interface SceneTransitionListener {
-        void enterSharedElement(Bundle transitionArgs);
         void nullPendingTransition();
         void convertFromTranslucent();
         void convertToTranslucent();
+        void sharedElementStart(Transition transition);
+        void sharedElementEnd();
     }
 
     /**
-     * Controls how the background fade is triggered. If fadeEarly is true, the Window background
-     * will fade in as soon as the shared elements are ready to switch. If fadeEarly is false,
-     * the background will fade only after the calling Activity's exit transition completes.
-     * By default, the Window will fade in when the calling Activity's exit transition completes.
+     * Controls when the Activity enter scene is triggered and the background is faded in. If
+     * triggerEarly is true, the enter scene will begin as soon as possible and the background
+     * will fade in when all shared elements are ready to begin transitioning. If triggerEarly is
+     * false, the Activity enter scene and background fade will be triggered when the calling
+     * Activity's exit transition completes.
      *
-     * @param fadeEarly Set to true to fade out the exiting Activity as soon as the shared elements
-     *                  are transferred. Set to false to fade out the exiting Activity as soon as
-     *                  the shared element is transferred.
-     * @hide
+     * @param triggerEarly Set to true to have the Activity enter scene transition in as early as
+     *                     possible or set to false to wait for the calling Activity to exit first.
      */
-    public void setEarlyBackgroundTransition(boolean fadeEarly) {
+    public void setTriggerEarlyEnterTransition(boolean triggerEarly) {
     }
 
     /**
      * Start the exit transition.
      * @hide
      */
-    public void startExitTransition(ActivityOptions activityOptions) {
+    public Bundle startExitTransition(ActivityOptions options) {
+        return null;
+    }
+
+    /**
+     * On entering Activity Scene transitions, shared element names may be mapped from a
+     * source Activity's specified name to a unique shared element name in the View hierarchy.
+     * Under most circumstances, mapping is not necessary - a single View will have the
+     * shared element name given by the calling Activity. However, if there are several similar
+     * Views (e.g. in a ListView), the correct shared element must be mapped.
+     * @param sharedElementNames A mapping from the calling Activity's assigned shared element
+     *                           name to a unique shared element name in the View hierarchy.
+     */
+    public void mapTransitionTargets(Map<String, String> sharedElementNames) {
     }
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 53a4c0d0..55956bf 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -98,7 +98,7 @@
      * the given view hierarchy's {@link View#onDetachedFromWindow()
      * View.onDetachedFromWindow()} methods before returning.  This is not
      * for normal applications; using it correctly requires great care.
-     * 
+     *
      * @param view The view to be removed.
      */
     public void removeViewImmediate(View view);
@@ -112,7 +112,7 @@
          */
         @ViewDebug.ExportedProperty
         public int x;
-        
+
         /**
          * Y position for this window.  With the default gravity it is ignored.
          * When using {@link Gravity#TOP} or {@link Gravity#BOTTOM} it provides
@@ -161,7 +161,7 @@
          * be used by applications, and a special permission is required
          * to use them.
          * </ul>
-         * 
+         *
          * @see #TYPE_BASE_APPLICATION
          * @see #TYPE_APPLICATION
          * @see #TYPE_APPLICATION_STARTING
@@ -223,12 +223,12 @@
             @ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION")
         })
         public int type;
-    
+
         /**
          * Start of window types that represent normal application windows.
          */
         public static final int FIRST_APPLICATION_WINDOW = 1;
-        
+
         /**
          * Window type: an application window that serves as the "base" window
          * of the overall application; all other application windows will
@@ -236,14 +236,14 @@
          * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_BASE_APPLICATION   = 1;
-        
+
         /**
          * Window type: a normal application window.  The {@link #token} must be
          * an Activity token identifying who the window belongs to.
          * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_APPLICATION        = 2;
-    
+
         /**
          * Window type: special application window that is displayed while the
          * application is starting.  Not for use by applications themselves;
@@ -252,12 +252,12 @@
          * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_APPLICATION_STARTING = 3;
-    
+
         /**
          * End of types of application windows.
          */
         public static final int LAST_APPLICATION_WINDOW = 99;
-    
+
         /**
          * Start of types of sub-windows.  The {@link #token} of these windows
          * must be set to the window they are attached to.  These types of
@@ -265,19 +265,19 @@
          * coordinate space is relative to their attached window.
          */
         public static final int FIRST_SUB_WINDOW        = 1000;
-    
+
         /**
          * Window type: a panel on top of an application window.  These windows
          * appear on top of their attached window.
          */
         public static final int TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW;
-    
+
         /**
          * Window type: window for showing media (such as video).  These windows
          * are displayed behind their attached window.
          */
         public static final int TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1;
-    
+
         /**
          * Window type: a sub-panel on top of an application window.  These
          * windows are displayed on top their attached window and any
@@ -290,7 +290,7 @@
          * as a child of its container.
          */
         public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3;
-        
+
         /**
          * Window type: window for showing overlays on top of media windows.
          * These windows are displayed between TYPE_APPLICATION_MEDIA and the
@@ -299,18 +299,18 @@
          * @hide
          */
         public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4;
-    
+
         /**
          * End of types of sub-windows.
          */
         public static final int LAST_SUB_WINDOW         = 1999;
-        
+
         /**
          * Start of system-specific window types.  These are not normally
          * created by applications.
          */
         public static final int FIRST_SYSTEM_WINDOW     = 2000;
-    
+
         /**
          * Window type: the status bar.  There can be only one status bar
          * window; it is placed at the top of the screen, and all other
@@ -318,14 +318,14 @@
          * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
-    
+
         /**
          * Window type: the search bar.  There can be only one search bar
          * window; it is placed at the top of the screen.
          * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
-    
+
         /**
          * Window type: phone.  These are non-application windows providing
          * user interaction with the phone (in particular incoming calls).
@@ -334,26 +334,26 @@
          * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
-    
+
         /**
          * Window type: system window, such as low power alert. These windows
          * are always on top of application windows.
          * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
-        
+
         /**
          * Window type: keyguard window.
          * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
-        
+
         /**
          * Window type: transient notifications.
          * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;
-        
+
         /**
          * Window type: system overlay windows, which need to be displayed
          * on top of everything else.  These windows must not take input
@@ -361,7 +361,7 @@
          * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
-        
+
         /**
          * Window type: priority phone UI, which needs to be displayed even if
          * the keyguard is active.  These windows must not take input
@@ -369,26 +369,26 @@
          * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;
-        
+
         /**
          * Window type: panel that slides out from the status bar
          * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;
-    
+
         /**
          * Window type: dialogs that the keyguard shows
          * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;
-        
+
         /**
          * Window type: internal system error windows, appear on top of
          * everything they can.
          * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
-        
+
         /**
          * Window type: internal input methods windows, which appear above
          * the normal UI.  Application windows may be resized or panned to keep
@@ -559,16 +559,16 @@
         /** @deprecated this is ignored, this value is set automatically when needed. */
         @Deprecated
         public static final int MEMORY_TYPE_PUSH_BUFFERS = 3;
-        
+
         /**
          * @deprecated this is ignored
          */
         @Deprecated
         public int memoryType;
-        
+
         /** Window flag: as long as this window is visible to the user, allow
-         *  the lock screen to activate while the screen is on. 
-         *  This can be used independently, or in combination with 
+         *  the lock screen to activate while the screen is on.
+         *  This can be used independently, or in combination with
          *  {@link #FLAG_KEEP_SCREEN_ON} and/or {@link #FLAG_SHOW_WHEN_LOCKED} */
         public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001;
 
@@ -586,47 +586,47 @@
          * instead go to whatever focusable window is behind it.  This flag
          * will also enable {@link #FLAG_NOT_TOUCH_MODAL} whether or not that
          * is explicitly set.
-         * 
+         *
          * <p>Setting this flag also implies that the window will not need to
          * interact with
-         * a soft input method, so it will be Z-ordered and positioned 
+         * a soft input method, so it will be Z-ordered and positioned
          * independently of any active input method (typically this means it
          * gets Z-ordered on top of the input method, so it can use the full
          * screen for its content and cover the input method if needed.  You
          * can use {@link #FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */
         public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;
-        
+
         /** Window flag: this window can never receive touch events. */
         public static final int FLAG_NOT_TOUCHABLE      = 0x00000010;
-        
+
         /** Window flag: even when this window is focusable (its
          * {@link #FLAG_NOT_FOCUSABLE} is not set), allow any pointer events
          * outside of the window to be sent to the windows behind it.  Otherwise
          * it will consume all pointer events itself, regardless of whether they
          * are inside of the window. */
         public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;
-        
+
         /** Window flag: when set, if the device is asleep when the touch
          * screen is pressed, you will receive this first touch event.  Usually
          * the first touch event is consumed by the system since the user can
          * not see what they are pressing on.
          */
         public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
-        
+
         /** Window flag: as long as this window is visible to the user, keep
          *  the device's screen turned on and bright. */
         public static final int FLAG_KEEP_SCREEN_ON     = 0x00000080;
-        
+
         /** Window flag: place the window within the entire screen, ignoring
          *  decorations around the border (such as the status bar).  The
          *  window must correctly position its contents to take the screen
          *  decoration into account.  This flag is normally set for you
          *  by Window as described in {@link Window#setFlags}. */
         public static final int FLAG_LAYOUT_IN_SCREEN   = 0x00000100;
-        
+
         /** Window flag: allow window to extend outside of the screen. */
         public static final int FLAG_LAYOUT_NO_LIMITS   = 0x00000200;
-        
+
         /**
          * Window flag: hide all screen decorations (such as the status bar) while
          * this window is displayed.  This allows the window to use the entire
@@ -648,17 +648,17 @@
          * {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_Fullscreen}.</p>
          */
         public static final int FLAG_FULLSCREEN      = 0x00000400;
-        
+
         /** Window flag: override {@link #FLAG_FULLSCREEN} and force the
          *  screen decorations (such as the status bar) to be shown. */
         public static final int FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800;
-        
+
         /** Window flag: turn on dithering when compositing this window to
          *  the screen.
          * @deprecated This flag is no longer used. */
         @Deprecated
         public static final int FLAG_DITHER             = 0x00001000;
-        
+
         /** Window flag: treat the content of the window as secure, preventing
          * it from appearing in screenshots or from being viewed on non-secure
          * displays.
@@ -667,21 +667,21 @@
          * secure surfaces and secure displays.
          */
         public static final int FLAG_SECURE             = 0x00002000;
-        
+
         /** Window flag: a special mode where the layout parameters are used
          * to perform scaling of the surface when it is composited to the
          * screen. */
         public static final int FLAG_SCALED             = 0x00004000;
-        
+
         /** Window flag: intended for windows that will often be used when the user is
          * holding the screen against their face, it will aggressively filter the event
          * stream to prevent unintended presses in this situation that may not be
-         * desired for a particular window, when such an event stream is detected, the 
+         * desired for a particular window, when such an event stream is detected, the
          * application will receive a CANCEL motion event to indicate this so applications
-         * can handle this accordingly by taking no action on the event 
+         * can handle this accordingly by taking no action on the event
          * until the finger is released. */
         public static final int FLAG_IGNORE_CHEEK_PRESSES    = 0x00008000;
-        
+
         /** Window flag: a special option only for use in combination with
          * {@link #FLAG_LAYOUT_IN_SCREEN}.  When requesting layout in the
          * screen your window may appear on top of or behind screen decorations
@@ -690,7 +690,7 @@
          * content is not covered by screen decorations.  This flag is normally
          * set for you by Window as described in {@link Window#setFlags}.*/
         public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
-        
+
         /** Window flag: invert the state of {@link #FLAG_NOT_FOCUSABLE} with
          * respect to how this window interacts with the current method.  That
          * is, if FLAG_NOT_FOCUSABLE is set and this flag is set, then the
@@ -701,7 +701,7 @@
          * to use more space and cover the input method.
          */
         public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;
-        
+
         /** Window flag: if you have set {@link #FLAG_NOT_TOUCH_MODAL}, you
          * can set this flag to receive a single special MotionEvent with
          * the action
@@ -711,7 +711,7 @@
          * first down as an ACTION_OUTSIDE.
          */
         public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;
-        
+
         /** Window flag: special flag to let windows be shown when the screen
          * is locked. This will let application windows take precedence over
          * key guard or any other lock screens. Can be used with
@@ -741,13 +741,13 @@
          * {@link android.R.style#Theme_DeviceDefault_Wallpaper_NoTitleBar}.</p>
          */
         public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
-        
+
         /** Window flag: when set as a window is being added or made
          * visible, once the window has been shown then the system will
          * poke the power manager's user activity (as if the user had woken
          * up the device) to turn the screen on. */
         public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
-        
+
         /** Window flag: when set the window will cause the keyguard to
          * be dismissed, only if it is not a secure lock keyguard.  Because such
          * a keyguard is not needed for security, it will never re-appear if
@@ -761,7 +761,7 @@
          * also been set.
          */
         public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
-        
+
         /** Window flag: when set the window will accept for touch events
          * outside of its bounds to be sent to other windows that also
          * support split touch.  When this flag is not set, the first pointer
@@ -773,7 +773,7 @@
          * to be split across multiple windows.
          */
         public static final int FLAG_SPLIT_TOUCH = 0x00800000;
-        
+
         /**
          * <p>Indicates whether this window should be hardware accelerated.
          * Requesting hardware acceleration does not guarantee it will happen.</p>
@@ -916,7 +916,7 @@
 
         /**
          * Various behavioral options/flags.  Default is none.
-         * 
+         *
          * @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
          * @see #FLAG_DIM_BEHIND
          * @see #FLAG_NOT_FOCUSABLE
@@ -1014,10 +1014,10 @@
          * as if it was.
          * Like {@link #FLAG_HARDWARE_ACCELERATED} except for trusted system windows
          * that need hardware acceleration (e.g. LockScreen), where hardware acceleration
-         * is generally disabled. This flag must be specified in addition to 
+         * is generally disabled. This flag must be specified in addition to
          * {@link #FLAG_HARDWARE_ACCELERATED} to enable hardware acceleration for system
          * windows.
-         * 
+         *
          * @hide
          */
         public static final int PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED = 0x00000001;
@@ -1028,7 +1028,7 @@
          * If certain parts of the UI that really do want to use hardware
          * acceleration, this flag can be set to force it.  This is basically
          * for the lock screen.  Anyone else using it, you are probably wrong.
-         * 
+         *
          * @hide
          */
         public static final int PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED = 0x00000002;
@@ -1086,6 +1086,11 @@
          * {@hide} */
         public static final int PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR = 0x00000200;
 
+        /** Window flag: the window is backed by a video plane, instead of a
+         * regular surface.
+         * {@hide} */
+        public static final int PRIVATE_FLAG_VIDEO_PLANE = 0x00000400;
+
         /**
          * Control flags that are private to the platform.
          * @hide
@@ -1100,9 +1105,9 @@
          * flags and returns true if the combination of the two corresponds
          * to a window that needs to be behind the input method so that the
          * user can type into it.
-         * 
+         *
          * @param flags The current window manager flags.
-         * 
+         *
          * @return Returns true if such a window should be behind/interact
          * with an input method, false if not.
          */
@@ -1114,63 +1119,63 @@
             }
             return false;
         }
-        
+
         /**
          * Mask for {@link #softInputMode} of the bits that determine the
          * desired visibility state of the soft input area for this window.
          */
         public static final int SOFT_INPUT_MASK_STATE = 0x0f;
-        
+
         /**
          * Visibility state for {@link #softInputMode}: no state has been specified.
          */
         public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
-        
+
         /**
          * Visibility state for {@link #softInputMode}: please don't change the state of
          * the soft input area.
          */
         public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
-        
+
         /**
          * Visibility state for {@link #softInputMode}: please hide any soft input
          * area when normally appropriate (when the user is navigating
          * forward to your window).
          */
         public static final int SOFT_INPUT_STATE_HIDDEN = 2;
-        
+
         /**
          * Visibility state for {@link #softInputMode}: please always hide any
          * soft input area when this window receives focus.
          */
         public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
-        
+
         /**
          * Visibility state for {@link #softInputMode}: please show the soft
          * input area when normally appropriate (when the user is navigating
          * forward to your window).
          */
         public static final int SOFT_INPUT_STATE_VISIBLE = 4;
-        
+
         /**
          * Visibility state for {@link #softInputMode}: please always make the
          * soft input area visible when this window receives input focus.
          */
         public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
-        
+
         /**
          * Mask for {@link #softInputMode} of the bits that determine the
          * way that the window should be adjusted to accommodate the soft
          * input window.
          */
         public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
-        
+
         /** Adjustment option for {@link #softInputMode}: nothing specified.
          * The system will try to pick one or
          * the other depending on the contents of the window.
          */
         public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
-        
+
         /** Adjustment option for {@link #softInputMode}: set to allow the
          * window to be resized when an input
          * method is shown, so that its contents are not covered by the input
@@ -1183,7 +1188,7 @@
          * not resize, but will stay fullscreen.
          */
         public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
-        
+
         /** Adjustment option for {@link #softInputMode}: set to have a window
          * pan when an input method is
          * shown, so it doesn't need to deal with resizing but just panned
@@ -1193,7 +1198,7 @@
          * the other depending on the contents of the window.
          */
         public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
-        
+
         /** Adjustment option for {@link #softInputMode}: set to have a window
          * not adjust for a shown input method.  The window will not be resized,
          * and it will not be panned to make its focus visible.
@@ -1212,7 +1217,7 @@
         /**
          * Desired operating mode for any soft input area.  May be any combination
          * of:
-         * 
+         *
          * <ul>
          * <li> One of the visibility states
          * {@link #SOFT_INPUT_STATE_UNSPECIFIED}, {@link #SOFT_INPUT_STATE_UNCHANGED},
@@ -1229,7 +1234,7 @@
          * {@link android.R.attr#windowSoftInputMode} attribute.</p>
          */
         public int softInputMode;
-        
+
         /**
          * Placement of window within the screen as per {@link Gravity}.  Both
          * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
@@ -1246,7 +1251,7 @@
          * @see Gravity
          */
         public int gravity;
-    
+
         /**
          * The horizontal margin, as a percentage of the container's width,
          * between the container and the widget.  See
@@ -1255,7 +1260,7 @@
          * field is added with {@link #x} to supply the <var>xAdj</var> parameter.
          */
         public float horizontalMargin;
-    
+
         /**
          * The vertical margin, as a percentage of the container's height,
          * between the container and the widget.  See
@@ -1264,26 +1269,26 @@
          * field is added with {@link #y} to supply the <var>yAdj</var> parameter.
          */
         public float verticalMargin;
-    
+
         /**
          * The desired bitmap format.  May be one of the constants in
          * {@link android.graphics.PixelFormat}.  Default is OPAQUE.
          */
         public int format;
-    
+
         /**
          * A style resource defining the animations to use for this window.
          * This must be a system resource; it can not be an application resource
          * because the window manager does not have access to applications.
          */
         public int windowAnimations;
-    
+
         /**
          * An alpha value to apply to this entire window.
          * An alpha of 1.0 means fully opaque and 0.0 means fully transparent
          */
         public float alpha = 1.0f;
-    
+
         /**
          * When {@link #FLAG_DIM_BEHIND} is set, this is the amount of dimming
          * to apply.  Range is from 1.0 for completely opaque to 0.0 for no
@@ -1311,7 +1316,7 @@
          * to the hightest value when this window is in front.
          */
         public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
-    
+
         /**
          * This can be used to override the user's preferred brightness of
          * the screen.  A value of less than 0, the default, means to use the
@@ -1319,7 +1324,7 @@
          * dark to full bright.
          */
         public float screenBrightness = BRIGHTNESS_OVERRIDE_NONE;
-        
+
         /**
          * This can be used to override the standard behavior of the button and
          * keyboard backlights.  A value of less than 0, the default, means to
@@ -1353,7 +1358,7 @@
          * opaque windows have the #FLAG_FULLSCREEN bit set and are not covered
          * by other windows. All other situations default to the
          * {@link #ROTATION_ANIMATION_ROTATE} behavior.
-         * 
+         *
          * @see #ROTATION_ANIMATION_ROTATE
          * @see #ROTATION_ANIMATION_CROSSFADE
          * @see #ROTATION_ANIMATION_JUMPCUT
@@ -1365,18 +1370,18 @@
          * you.
          */
         public IBinder token = null;
-    
+
         /**
          * Name of the package owning this window.
          */
         public String packageName = null;
-        
+
         /**
          * Specific orientation value for a window.
          * May be any of the same values allowed
-         * for {@link android.content.pm.ActivityInfo#screenOrientation}. 
-         * If not set, a default value of 
-         * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} 
+         * for {@link android.content.pm.ActivityInfo#screenOrientation}.
+         * If not set, a default value of
+         * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}
          * will be used.
          */
         public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -1398,7 +1403,7 @@
 
         /**
          * Get callbacks about the system ui visibility changing.
-         * 
+         *
          * TODO: Maybe there should be a bitfield of optional callbacks that we need.
          *
          * @hide
@@ -1464,34 +1469,34 @@
             type = TYPE_APPLICATION;
             format = PixelFormat.OPAQUE;
         }
-        
+
         public LayoutParams(int _type) {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
             type = _type;
             format = PixelFormat.OPAQUE;
         }
-    
+
         public LayoutParams(int _type, int _flags) {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
             type = _type;
             flags = _flags;
             format = PixelFormat.OPAQUE;
         }
-    
+
         public LayoutParams(int _type, int _flags, int _format) {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
             type = _type;
             flags = _flags;
             format = _format;
         }
-        
+
         public LayoutParams(int w, int h, int _type, int _flags, int _format) {
             super(w, h);
             type = _type;
             flags = _flags;
             format = _format;
         }
-        
+
         public LayoutParams(int w, int h, int xpos, int ypos, int _type,
                 int _flags, int _format) {
             super(w, h);
@@ -1501,18 +1506,18 @@
             flags = _flags;
             format = _format;
         }
-    
+
         public final void setTitle(CharSequence title) {
             if (null == title)
                 title = "";
-    
+
             mTitle = TextUtils.stringOrSpannedString(title);
         }
-    
+
         public final CharSequence getTitle() {
             return mTitle;
         }
-    
+
         public int describeContents() {
             return 0;
         }
@@ -1546,19 +1551,19 @@
             out.writeInt(inputFeatures);
             out.writeLong(userActivityTimeout);
         }
-        
+
         public static final Parcelable.Creator<LayoutParams> CREATOR
                     = new Parcelable.Creator<LayoutParams>() {
             public LayoutParams createFromParcel(Parcel in) {
                 return new LayoutParams(in);
             }
-    
+
             public LayoutParams[] newArray(int size) {
                 return new LayoutParams[size];
             }
         };
-    
-    
+
+
         public LayoutParams(Parcel in) {
             width = in.readInt();
             height = in.readInt();
@@ -1588,7 +1593,7 @@
             inputFeatures = in.readInt();
             userActivityTimeout = in.readLong();
         }
-    
+
         @SuppressWarnings({"PointlessBitwiseExpression"})
         public static final int LAYOUT_CHANGED = 1<<0;
         public static final int TYPE_CHANGED = 1<<1;
@@ -1622,10 +1627,10 @@
 
         // internal buffer to backup/restore parameters under compatibility mode.
         private int[] mCompatibilityParamsBackup = null;
-        
+
         public final int copyFrom(LayoutParams o) {
             int changes = 0;
-    
+
             if (width != o.width) {
                 width = o.width;
                 changes |= LAYOUT_CHANGED;
@@ -1724,7 +1729,7 @@
                 rotationAnimation = o.rotationAnimation;
                 changes |= ROTATION_ANIMATION_CHANGED;
             }
-    
+
             if (screenOrientation != o.screenOrientation) {
                 screenOrientation = o.screenOrientation;
                 changes |= SCREEN_ORIENTATION_CHANGED;
@@ -1754,7 +1759,7 @@
 
             return changes;
         }
-    
+
         @Override
         public String debug(String output) {
             output += "Contents of " + this + ":";
@@ -1765,7 +1770,7 @@
             Log.d("Debug", "WindowManager.LayoutParams={title=" + mTitle + "}");
             return "";
         }
-    
+
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder(256);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 86fdae3..47d42dc 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -56,7 +56,6 @@
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.ViewParent;
-import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -2313,6 +2312,7 @@
 
                 // If we failed to re-bind the data, scrap the obtained view.
                 if (updatedView != transientView) {
+                    setItemViewLayoutParams(updatedView, position);
                     mRecycler.addScrapView(updatedView, position);
                 }
             }
@@ -2343,19 +2343,7 @@
             child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
         }
 
-        if (mAdapterHasStableIds) {
-            final ViewGroup.LayoutParams vlp = child.getLayoutParams();
-            LayoutParams lp;
-            if (vlp == null) {
-                lp = (LayoutParams) generateDefaultLayoutParams();
-            } else if (!checkLayoutParams(vlp)) {
-                lp = (LayoutParams) generateLayoutParams(vlp);
-            } else {
-                lp = (LayoutParams) vlp;
-            }
-            lp.itemId = mAdapter.getItemId(position);
-            child.setLayoutParams(lp);
-        }
+        setItemViewLayoutParams(child, position);
 
         if (AccessibilityManager.getInstance(mContext).isEnabled()) {
             if (mAccessibilityDelegate == null) {
@@ -2371,6 +2359,24 @@
         return child;
     }
 
+    private void setItemViewLayoutParams(View child, int position) {
+        final ViewGroup.LayoutParams vlp = child.getLayoutParams();
+        LayoutParams lp;
+        if (vlp == null) {
+            lp = (LayoutParams) generateDefaultLayoutParams();
+        } else if (!checkLayoutParams(vlp)) {
+            lp = (LayoutParams) generateLayoutParams(vlp);
+        } else {
+            lp = (LayoutParams) vlp;
+        }
+
+        if (mAdapterHasStableIds) {
+            lp.itemId = mAdapter.getItemId(position);
+        }
+        lp.viewType = mAdapter.getItemViewType(position);
+        child.setLayoutParams(lp);
+    }
+
     class ListItemAccessibilityDelegate extends AccessibilityDelegate {
         @Override
         public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) {
@@ -4472,6 +4478,7 @@
      * scroll such that the indicated position is displayed, but it will
      * stop early if scrolling further would scroll boundPosition out of
      * view.
+     *
      * @param position Scroll to this adapter position.
      * @param boundPosition Do not scroll if it would move this adapter
      *          position out of view.
@@ -7121,7 +7128,10 @@
      * understanding of layout.
      */
     abstract class AbsSubPositionScroller extends AbsPositionScroller {
-        private static final int DEFAULT_SCROLL_DURATION = 200;
+        private static final int DURATION_AUTO = -1;
+
+        private static final int DURATION_AUTO_MIN = 100;
+        private static final int DURATION_AUTO_MAX = 500;
 
         private final SubScroller mSubScroller = new SubScroller();
 
@@ -7150,9 +7160,17 @@
                 return;
             }
 
+            if (mAdapter == null) {
+                // Can't scroll anywhere without an adapter.
+                return;
+            }
+
+            final int itemCount = getCount();
+            final int clampedPosition = MathUtils.constrain(targetPosition, 0, itemCount - 1);
+            final int clampedBoundPosition = MathUtils.constrain(boundPosition, 0, itemCount - 1);
             final int firstPosition = getFirstVisiblePosition();
             final int lastPosition = firstPosition + getChildCount();
-            final int targetRow = getRowForPosition(targetPosition);
+            final int targetRow = getRowForPosition(clampedPosition);
             final int firstRow = getRowForPosition(firstPosition);
             final int lastRow = getRowForPosition(lastPosition);
             if (useOffset || targetRow <= firstRow) {
@@ -7161,15 +7179,15 @@
             } else if (targetRow >= lastRow - 1) {
                 // Offset so the target row is bottom-aligned.
                 final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom();
-                mOffset = listHeight - getHeightForPosition(targetPosition);
+                mOffset = getHeightForPosition(clampedPosition) - listHeight;
             } else {
                 // Don't scroll, target is entirely on-screen.
                 return;
             }
 
             float endSubRow = targetRow;
-            if (boundPosition != INVALID_POSITION) {
-                final int boundRow = getRowForPosition(boundPosition);
+            if (clampedBoundPosition != INVALID_POSITION) {
+                final int boundRow = getRowForPosition(clampedBoundPosition);
                 if (boundRow >= firstRow && boundRow < lastRow && boundRow != targetRow) {
                     endSubRow = computeBoundSubRow(targetRow, boundRow);
                 }
@@ -7183,51 +7201,75 @@
             final int firstChildHeight = firstChild.getHeight();
             final float startOffsetRatio;
             if (firstChildHeight == 0) {
-                startOffsetRatio = 1;
+                startOffsetRatio = 0;
             } else {
                 startOffsetRatio = -firstChild.getTop() / (float) firstChildHeight;
             }
 
-            final float startSubRow = firstRow + startOffsetRatio;
+            final float startSubRow = MathUtils.constrain(
+                    firstRow + startOffsetRatio, 0, getCount());
             if (startSubRow == endSubRow && mOffset == 0) {
                 // Don't scroll, target is already in position.
                 return;
             }
 
-            mSubScroller.startScroll(startSubRow, endSubRow, duration);
+            final int durationMillis;
+            if (duration == DURATION_AUTO) {
+                final float subRowDelta = Math.abs(startSubRow - endSubRow);
+                durationMillis = (int) MathUtils.lerp(
+                        DURATION_AUTO_MIN, DURATION_AUTO_MAX, subRowDelta / getCount());
+            } else {
+                durationMillis = duration;
+            }
+
+            mSubScroller.startScroll(startSubRow, endSubRow, durationMillis);
 
             postOnAnimation(mAnimationFrame);
         }
 
-        private float computeBoundSubRow(int targetRow, int boundRow) {
-            // If the final offset is greater than 0, we're aiming above the
-            // suggested target row. Compute the actual target row and offset
-            // within that row by subtracting the height of each preceeding row.
-            int remainingOffset = mOffset;
+        /**
+         * Given a target row and offset, computes the sub-row position that
+         * aligns with the top of the list. If the offset is negative, the
+         * resulting sub-row will be smaller than the target row.
+         */
+        private float resolveOffset(int targetRow, int offset) {
+            // Compute the target sub-row position by finding the actual row
+            // indicated by the target and offset.
+            int remainingOffset = offset;
             int targetHeight = getHeightForRow(targetRow);
-            while (targetRow > 1 && remainingOffset > targetHeight) {
-                targetRow--;
-                remainingOffset -= targetHeight;
-                targetHeight = getHeightForRow(targetRow);
+            if (offset < 0) {
+                // Subtract row heights until we find the right row.
+                while (targetRow > 0 && remainingOffset < 0) {
+                    remainingOffset += targetHeight;
+                    targetRow--;
+                    targetHeight = getHeightForRow(targetRow);
+                }
+            } else if (offset > 0) {
+                // Add row heights until we find the right row.
+                while (targetRow < getCount() - 1 && remainingOffset > targetHeight) {
+                    remainingOffset -= targetHeight;
+                    targetRow++;
+                    targetHeight = getHeightForRow(targetRow);
+                }
             }
 
-            // Compute the offset within the actual target row.
             final float targetOffsetRatio;
-            if (remainingOffset > 0) {
-                // We can't reach that offset given the row count.
+            if (remainingOffset < 0 || targetHeight == 0) {
                 targetOffsetRatio = 0;
-            } else if (targetHeight == 0) {
-                targetOffsetRatio = 1;
             } else {
                 targetOffsetRatio = remainingOffset / (float) targetHeight;
             }
 
-            // The final offset has been accounted for, reset it.
-            final float targetSubRow = targetRow - targetOffsetRatio;
+            return targetRow + targetOffsetRatio;
+        }
+
+        private float computeBoundSubRow(int targetRow, int boundRow) {
+            final float targetSubRow = resolveOffset(targetRow, mOffset);
             mOffset = 0;
 
+            // The target row is below the bound row, so the end position would
+            // push the bound position above the list. Abort!
             if (targetSubRow >= boundRow) {
-                // End position would push the bound position above the list.
                 return boundRow;
             }
 
@@ -7235,39 +7277,24 @@
             // bound position's view further below the list.
             final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom();
             final int boundHeight = getHeightForRow(boundRow);
-            int endRow = boundRow;
-            int totalHeight = boundHeight;
-            int endHeight;
-            do {
-                endRow--;
-                endHeight = getHeightForRow(endRow);
-                totalHeight += endHeight;
-            } while (totalHeight < listHeight && endRow > 0);
+            final float boundSubRow = resolveOffset(boundRow, -listHeight + boundHeight);
 
-            final float endOffsetRatio;
-            if (endHeight == 0) {
-                endOffsetRatio = 1;
-            } else {
-                endOffsetRatio = (totalHeight - listHeight) / (float) endHeight;
-            }
-
-            final float boundSubRow = endRow + endOffsetRatio;
             return Math.max(boundSubRow, targetSubRow);
         }
 
         @Override
         public void start(int position) {
-            scrollToPosition(position, false, 0, INVALID_POSITION, DEFAULT_SCROLL_DURATION);
+            scrollToPosition(position, false, 0, INVALID_POSITION, DURATION_AUTO);
         }
 
         @Override
         public void start(int position, int boundPosition) {
-            scrollToPosition(position, false, 0, boundPosition, DEFAULT_SCROLL_DURATION);
+            scrollToPosition(position, false, 0, boundPosition, DURATION_AUTO);
         }
 
         @Override
         public void startWithOffset(int position, int offset) {
-            scrollToPosition(position, true, offset, INVALID_POSITION, DEFAULT_SCROLL_DURATION);
+            scrollToPosition(position, true, offset, INVALID_POSITION, DURATION_AUTO);
         }
 
         @Override
@@ -7319,7 +7346,7 @@
             final int rowHeight = getHeightForRow(row);
             final int offset = (int) (rowHeight * (subRow - row));
             final int addOffset = (int) (mOffset * mSubScroller.getInterpolatedValue());
-            setSelectionFromTop(position, -offset + addOffset);
+            setSelectionFromTop(position, -offset - addOffset);
 
             if (shouldPost) {
                 postOnAnimation(mAnimationFrame);
@@ -7338,7 +7365,7 @@
      * Scroller capable of returning floating point positions.
      */
     static class SubScroller {
-        private final Interpolator mInterpolator;
+        private static final Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator();
 
         private float mStartPosition;
         private float mEndPosition;
@@ -7348,18 +7375,6 @@
         private float mPosition;
         private float mInterpolatedValue;
 
-        public SubScroller() {
-            this(null);
-        }
-
-        public SubScroller(Interpolator interpolator) {
-            if (interpolator == null) {
-                mInterpolator = new AccelerateDecelerateInterpolator();
-            } else {
-                mInterpolator = interpolator;
-            }
-        }
-
         public void startScroll(float startPosition, float endPosition, int duration) {
             mStartPosition = startPosition;
             mEndPosition = endPosition;
@@ -7379,7 +7394,7 @@
                 value = MathUtils.constrain(elapsed / (float) mDuration, 0, 1);
             }
 
-            mInterpolatedValue = mInterpolator.getInterpolation(value);
+            mInterpolatedValue = INTERPOLATOR.getInterpolation(value);
             mPosition = (mEndPosition - mStartPosition) * mInterpolatedValue + mStartPosition;
 
             return elapsed < mDuration;
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index af9e2f0..f7e81b8 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -346,19 +346,24 @@
             return out;
             
         } else if (drawable instanceof BitmapDrawable) {
-            final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
+            final BitmapDrawable bitmap = (BitmapDrawable) drawable;
+            final Bitmap tileBitmap = bitmap.getBitmap();
             if (mSampleTile == null) {
                 mSampleTile = tileBitmap;
             }
-            
-            final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
 
+            final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
             final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
                     Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
             shapeDrawable.getPaint().setShader(bitmapShader);
 
-            return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
-                    ClipDrawable.HORIZONTAL) : shapeDrawable;
+            // Ensure the color filter and tint are propagated.
+            shapeDrawable.setTint(bitmap.getTint());
+            shapeDrawable.setTintMode(bitmap.getTintMode());
+            shapeDrawable.setColorFilter(bitmap.getColorFilter());
+
+            return clip ? new ClipDrawable(
+                    shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL) : shapeDrawable;
         }
         
         return drawable;
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 0a80495..cc51a8b 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -57,6 +57,7 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Map;
 
 /**
  * ActionBarImpl is the ActionBar implementation used
@@ -355,6 +356,10 @@
         setSubtitle(mContext.getString(resId));
     }
 
+    public void captureSharedElements(Map<String, View> sharedElements) {
+        mContainerView.findSharedElements(sharedElements);
+    }
+
     public void setSelectedNavigationItem(int position) {
         switch (mActionView.getNavigationMode()) {
         case NAVIGATION_MODE_TABS:
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1155cbb..3f90f76 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -35,11 +35,12 @@
 
     void noteEvent(int code, String name, int uid);
 
-    void noteStartWakelock(int uid, int pid, String name, int type, boolean unimportantForLogging);
+    void noteStartWakelock(int uid, int pid, String name, String historyName,
+            int type, boolean unimportantForLogging);
     void noteStopWakelock(int uid, int pid, String name, int type);
 
-    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type,
-            boolean unimportantForLogging);
+    void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, String historyName,
+            int type, boolean unimportantForLogging);
     void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
 
     void noteVibratorOn(int uid, long durationMillis);
@@ -51,7 +52,7 @@
     void noteScreenOff();
     void noteInputEvent();
     void noteUserActivity(int uid, int event);
-    void noteDataConnectionActive(String label, boolean active);
+    void noteDataConnectionActive(int type, boolean active);
     void notePhoneOn();
     void notePhoneOff();
     void notePhoneSignalStrength(in SignalStrength signalStrength);
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 2fe2494..a604d84 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -233,7 +233,9 @@
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
         while (++mRestorePackage < mRestorePackages.length) {
             String name = mRestorePackages[mRestorePackage].packageName;
-            if (new File(mDataDir, name).isDirectory()) {
+            // skip packages where we have a data dir but no actual contents
+            String[] contents = (new File(mDataDir, name)).list();
+            if (contents != null && contents.length > 0) {
                 if (DEBUG) Log.v(TAG, "  nextRestorePackage() = " + name);
                 return name;
             }
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index 4eff5ac..6ca24d7 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -34,6 +34,9 @@
     public long wakeLockTime;
     public long mobileRxPackets;
     public long mobileTxPackets;
+    public long mobileActive;
+    public int mobileActiveCount;
+    public double mobilemspp;         // milliseconds per packet
     public long wifiRxPackets;
     public long wifiTxPackets;
     public long mobileRxBytes;
@@ -69,6 +72,11 @@
         return values;
     }
 
+    public void computeMobilemspp() {
+        long packets = mobileRxPackets+mobileTxPackets;
+        mobilemspp = packets > 0 ? (mobileActive / (double)packets) : 0;
+    }
+
     @Override
     public int compareTo(BatterySipper other) {
         // Return the flipped value because we want the items in descending order
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index e0cf435..6f95937 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -43,6 +43,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 
@@ -73,6 +74,8 @@
             = new SparseArray<List<BatterySipper>>();
     private final SparseArray<Double> mUserPower = new SparseArray<Double>();
 
+    private final List<BatterySipper> mMobilemsppList = new ArrayList<BatterySipper>();
+
     private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
     private int mAsUser = 0;
 
@@ -90,6 +93,9 @@
     private double mMinDrainedPower;
     private double mMaxDrainedPower;
 
+    // How much the apps together have kept the mobile radio active.
+    private long mAppMobileActive;
+
     // How much the apps together have left WIFI running.
     private long mAppWifiRunning;
 
@@ -132,7 +138,7 @@
     }
 
     public static String makemAh(double power) {
-        if (power < .0001) return String.format("%.8f", power);
+        if (power < .00001) return String.format("%.8f", power);
         else if (power < .0001) return String.format("%.7f", power);
         else if (power < .001) return String.format("%.6f", power);
         else if (power < .01) return String.format("%.5f", power);
@@ -160,6 +166,7 @@
         mTotalPower = 0;
         mWifiPower = 0;
         mBluetoothPower = 0;
+        mAppMobileActive = 0;
         mAppWifiRunning = 0;
 
         mUsageList.clear();
@@ -167,6 +174,7 @@
         mBluetoothSippers.clear();
         mUserSippers.clear();
         mUserPower.clear();
+        mMobilemsppList.clear();
 
         if (mStats == null) {
             return;
@@ -193,6 +201,37 @@
                 * mPowerProfile.getBatteryCapacity()) / 100;
 
         processAppUsage();
+
+        // Before aggregating apps in to users, collect all apps to sort by their ms per packet.
+        for (int i=0; i<mUsageList.size(); i++) {
+            BatterySipper bs = mUsageList.get(i);
+            bs.computeMobilemspp();
+            if (bs.mobilemspp != 0) {
+                mMobilemsppList.add(bs);
+            }
+        }
+        for (int i=0; i<mUserSippers.size(); i++) {
+            List<BatterySipper> user = mUserSippers.valueAt(i);
+            for (int j=0; j<user.size(); j++) {
+                BatterySipper bs = user.get(j);
+                bs.computeMobilemspp();
+                if (bs.mobilemspp != 0) {
+                    mMobilemsppList.add(bs);
+                }
+            }
+        }
+        Collections.sort(mMobilemsppList, new Comparator<BatterySipper>() {
+            @Override
+            public int compare(BatterySipper lhs, BatterySipper rhs) {
+                if (lhs.mobilemspp < rhs.mobilemspp) {
+                    return 1;
+                } else if (lhs.mobilemspp > rhs.mobilemspp) {
+                    return -1;
+                }
+                return 0;
+            }
+        });
+
         processMiscUsage();
 
         if (DEBUG) {
@@ -225,6 +264,7 @@
             powerCpuNormal[p] = mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p);
         }
         final double mobilePowerPerPacket = getMobilePowerPerPacket();
+        final double mobilePowerPerMs = getMobilePowerPerMs();
         final double wifiPowerPerPacket = getWifiPowerPerPacket();
         long appWakelockTime = 0;
         BatterySipper osApp = null;
@@ -320,9 +360,20 @@
             final long mobileTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
             final long mobileRxB = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType);
             final long mobileTxB = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType);
-            p = (mobileRx + mobileTx) * mobilePowerPerPacket;
+            final long mobileActive = u.getMobileRadioActiveTime(mStatsType);
+            if (mobileActive > 0) {
+                // We are tracking when the radio is up, so can use the active time to
+                // determine power use.
+                mAppMobileActive += mobileActive;
+                p = (mobilePowerPerMs * mobileActive) / 1000;
+            } else {
+                // We are not tracking when the radio is up, so must approximate power use
+                // based on the number of packets.
+                p = (mobileRx + mobileTx) * mobilePowerPerPacket;
+            }
             if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
-                    + (mobileRx+mobileTx) + " power=" + makemAh(p));
+                    + (mobileRx+mobileTx) + " active time " + mobileActive
+                    + " power=" + makemAh(p));
             power += p;
 
             // Add cost of wifi traffic
@@ -406,6 +457,8 @@
                 app.wakeLockTime = wakelockTime;
                 app.mobileRxPackets = mobileRx;
                 app.mobileTxPackets = mobileTx;
+                app.mobileActive = mobileActive / 1000;
+                app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType);
                 app.wifiRxPackets = wifiRx;
                 app.wifiTxPackets = wifiTx;
                 app.mobileRxBytes = mobileRxB;
@@ -474,7 +527,7 @@
         double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
                 * phoneOnTimeMs / (60*60*1000);
         if (phoneOnPower != 0) {
-            addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower);
+            BatterySipper bs = addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower);
         }
     }
 
@@ -531,12 +584,19 @@
             Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + makemAh(p));
         }
         power += p;
+        long radioActiveTimeUs = mStats.getMobileRadioActiveTime(mBatteryRealtime, mStatsType);
+        long remainingActiveTime = (radioActiveTimeUs - mAppMobileActive) / 1000;
+        if (remainingActiveTime > 0) {
+            power += getMobilePowerPerMs() * remainingActiveTime;
+        }
         if (power != 0) {
             BatterySipper bs =
                     addEntry(BatterySipper.DrainType.CELL, signalTimeMs, power);
             if (signalTimeMs != 0) {
                 bs.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs;
             }
+            bs.mobileActive = remainingActiveTime;
+            bs.mobileActiveCount = mStats.getMobileRadioActiveUnknownCount(mStatsType);
         }
     }
 
@@ -551,6 +611,8 @@
             bs.wakeLockTime += wbs.wakeLockTime;
             bs.mobileRxPackets += wbs.mobileRxPackets;
             bs.mobileTxPackets += wbs.mobileTxPackets;
+            bs.mobileActive += wbs.mobileActive;
+            bs.mobileActiveCount += wbs.mobileActiveCount;
             bs.wifiRxPackets += wbs.wifiRxPackets;
             bs.wifiTxPackets += wbs.wifiTxPackets;
             bs.mobileRxBytes += wbs.mobileRxBytes;
@@ -558,6 +620,7 @@
             bs.wifiRxBytes += wbs.wifiRxBytes;
             bs.wifiTxBytes += wbs.wifiTxBytes;
         }
+        bs.computeMobilemspp();
     }
 
     private void addWiFiUsage() {
@@ -650,6 +713,13 @@
     }
 
     /**
+     * Return estimated power (in mAs) of keeping the radio up
+     */
+    private double getMobilePowerPerMs() {
+        return mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE) / (60*60*1000);
+    }
+
+    /**
      * Return estimated power (in mAs) of sending a byte with the Wi-Fi radio.
      */
     private double getWifiPowerPerPacket() {
@@ -691,6 +761,10 @@
         return mUsageList;
     }
 
+    public List<BatterySipper> getMobilemsppList() {
+        return mMobilemsppList;
+    }
+
     public long getStatsPeriod() { return mStatsPeriod; }
 
     public int getStatsType() { return mStatsType; };
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 40e8727..fdb090b 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -87,7 +87,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 85 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 94 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -283,6 +283,9 @@
 
     boolean mMobileRadioActive;
     StopwatchTimer mMobileRadioActiveTimer;
+    StopwatchTimer mMobileRadioActivePerAppTimer;
+    LongSamplingCounter mMobileRadioActiveUnknownTime;
+    LongSamplingCounter mMobileRadioActiveUnknownCount;
 
     /** Bluetooth headset object */
     BluetoothHeadset mBtHeadset;
@@ -1176,11 +1179,12 @@
 
         void startRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
             if (mNesting++ == 0) {
-                mUpdateTime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000);
+                final long batteryRealtime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000);
+                mUpdateTime = batteryRealtime;
                 if (mTimerPool != null) {
                     // Accumulate time to all currently active timers before adding
                     // this new one to the pool.
-                    refreshTimersLocked(stats, mTimerPool);
+                    refreshTimersLocked(stats, batteryRealtime, mTimerPool, null);
                     // Add this timer to the active pool
                     mTimerPool.add(this);
                 }
@@ -1199,21 +1203,35 @@
             return mNesting > 0;
         }
 
+        long checkpointRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
+            if (mNesting > 0) {
+                // We are running...
+                final long batteryRealtime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000);
+                if (mTimerPool != null) {
+                    return refreshTimersLocked(stats, batteryRealtime, mTimerPool, this);
+                }
+                final long heldTime = batteryRealtime - mUpdateTime;
+                mUpdateTime = batteryRealtime;
+                mTotalTime += heldTime;
+                return heldTime;
+            }
+            return 0;
+        }
+
         void stopRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
             // Ignore attempt to stop a timer that isn't running
             if (mNesting == 0) {
                 return;
             }
             if (--mNesting == 0) {
+                final long batteryRealtime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000);
                 if (mTimerPool != null) {
                     // Accumulate time to all active counters, scaled by the total
                     // active in the pool, before taking this one out of the pool.
-                    refreshTimersLocked(stats, mTimerPool);
+                    refreshTimersLocked(stats, batteryRealtime, mTimerPool, null);
                     // Remove this timer from the active pool
                     mTimerPool.remove(this);
                 } else {
-                    final long batteryRealtime = stats.getBatteryRealtimeLocked(
-                            elapsedRealtime * 1000);
                     mNesting = 1;
                     mTotalTime = computeRunTimeLocked(batteryRealtime);
                     mNesting = 0;
@@ -1235,19 +1253,23 @@
 
         // Update the total time for all other running Timers with the same type as this Timer
         // due to a change in timer count
-        private static void refreshTimersLocked(final BatteryStatsImpl stats,
-                final ArrayList<StopwatchTimer> pool) {
-            final long realtime = SystemClock.elapsedRealtime() * 1000;
-            final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
+        private static long refreshTimersLocked(final BatteryStatsImpl stats,
+                long batteryRealtime, final ArrayList<StopwatchTimer> pool, StopwatchTimer self) {
+            long selfTime = 0;
             final int N = pool.size();
             for (int i=N-1; i>= 0; i--) {
                 final StopwatchTimer t = pool.get(i);
                 long heldTime = batteryRealtime - t.mUpdateTime;
                 if (heldTime > 0) {
-                    t.mTotalTime += heldTime / N;
+                    final long myTime = heldTime / N;
+                    if (t == self) {
+                        selfTime = myTime;
+                    }
+                    t.mTotalTime += myTime;
                 }
                 t.mUpdateTime = batteryRealtime;
             }
+            return selfTime;
         }
 
         @Override
@@ -2011,7 +2033,7 @@
         addHistoryEventLocked(SystemClock.elapsedRealtime(), code, name, uid);
     }
 
-    public void noteStartWakeLocked(int uid, int pid, String name, int type,
+    public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
             boolean unimportantForLogging) {
         uid = mapUid(uid);
         final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -2023,7 +2045,7 @@
                 if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
                         + Integer.toHexString(mHistoryCur.states));
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                mHistoryCur.wakelockTag.string = name;
+                mHistoryCur.wakelockTag.string = historyName != null ? historyName : name;
                 mHistoryCur.wakelockTag.uid = uid;
                 mWakeLockImportant = !unimportantForLogging;
                 addHistoryRecordLocked(elapsedRealtime);
@@ -2032,7 +2054,7 @@
                     // We'll try to update the last tag.
                     mHistoryLastWritten.wakelockTag = null;
                     mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                    mHistoryCur.wakelockTag.string = name;
+                    mHistoryCur.wakelockTag.string = historyName != null ? historyName : name;
                     mHistoryCur.wakelockTag.uid = uid;
                     addHistoryRecordLocked(elapsedRealtime);
                 }
@@ -2070,11 +2092,11 @@
         }
     }
 
-    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type,
-            boolean unimportantForLogging) {
+    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
+            String historyName, int type, boolean unimportantForLogging) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
-            noteStartWakeLocked(ws.get(i), pid, name, type, unimportantForLogging);
+            noteStartWakeLocked(ws.get(i), pid, name, historyName, type, unimportantForLogging);
         }
     }
 
@@ -2291,7 +2313,8 @@
 
             // Fake a wake lock, so we consider the device waked as long
             // as the screen is on.
-            noteStartWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL, false);
+            noteStartWakeLocked(Process.myUid(), Process.myPid(), "screen", null,
+                    WAKE_TYPE_PARTIAL, false);
             
             // Update discharge amounts.
             if (mOnBatteryInternal) {
@@ -2351,29 +2374,31 @@
     }
 
     public void noteUserActivityLocked(int uid, int event) {
-        uid = mapUid(uid);
-        getUidStatsLocked(uid).noteUserActivityLocked(event);
+        if (mOnBatteryInternal) {
+            uid = mapUid(uid);
+            getUidStatsLocked(uid).noteUserActivityLocked(event);
+        }
     }
 
-    public void noteDataConnectionActive(String label, boolean active) {
-        try {
-            int type = Integer.parseInt(label);
-            if (ConnectivityManager.isNetworkTypeMobile(type)) {
-                final long elapsedRealtime = SystemClock.elapsedRealtime();
-                if (mMobileRadioActive != active) {
-                    if (active) mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
-                    else mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
-                    if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
-                            + Integer.toHexString(mHistoryCur.states));
-                    addHistoryRecordLocked(elapsedRealtime);
-                    mMobileRadioActive = active;
-                    if (active) mMobileRadioActiveTimer.startRunningLocked(this, elapsedRealtime);
-                    else mMobileRadioActiveTimer.stopRunningLocked(this, elapsedRealtime);
+    public void noteDataConnectionActive(int type, boolean active) {
+        if (ConnectivityManager.isNetworkTypeMobile(type)) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            if (mMobileRadioActive != active) {
+                if (active) mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+                else mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+                if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
+                        + Integer.toHexString(mHistoryCur.states));
+                addHistoryRecordLocked(elapsedRealtime);
+                mMobileRadioActive = active;
+                if (active) {
+                    mMobileRadioActiveTimer.startRunningLocked(this, elapsedRealtime);
+                    mMobileRadioActivePerAppTimer.startRunningLocked(this, elapsedRealtime);
+                } else {
+                    updateNetworkActivityLocked(NET_UPDATE_MOBILE, elapsedRealtime);
+                    mMobileRadioActiveTimer.stopRunningLocked(this, elapsedRealtime);
+                    mMobileRadioActivePerAppTimer.stopRunningLocked(this, elapsedRealtime);
                 }
             }
-        } catch (NumberFormatException e) {
-            Slog.w(TAG, "Bad data connection label: " + label, e);
-            return;
         }
     }
 
@@ -3005,13 +3030,17 @@
         // During device boot, qtaguid isn't enabled until after the inital
         // loading of battery stats. Now that they're enabled, take our initial
         // snapshot for future delta calculation.
-        updateNetworkActivityLocked();
+        updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
     }
 
     @Override public long getScreenOnTime(long batteryRealtime, int which) {
         return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
 
+    @Override public int getScreenOnCount(int which) {
+        return mScreenOnTimer.getCountLocked(which);
+    }
+
     @Override public long getScreenBrightnessTime(int brightnessBin,
             long batteryRealtime, int which) {
         return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
@@ -3026,6 +3055,10 @@
         return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
 
+    @Override public int getPhoneOnCount(int which) {
+        return mPhoneOnTimer.getCountLocked(which);
+    }
+
     @Override public long getPhoneSignalStrengthTime(int strengthBin,
             long batteryRealtime, int which) {
         return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
@@ -3056,6 +3089,18 @@
         return mMobileRadioActiveTimer.getTotalTimeLocked(batteryRealtime, which);
     }
 
+    @Override public int getMobileRadioActiveCount(int which) {
+        return mMobileRadioActiveTimer.getCountLocked(which);
+    }
+
+    @Override public long getMobileRadioActiveUnknownTime(int which) {
+        return mMobileRadioActiveUnknownTime.getCountLocked(which);
+    }
+
+    @Override public int getMobileRadioActiveUnknownCount(int which) {
+        return (int)mMobileRadioActiveUnknownCount.getCountLocked(which);
+    }
+
     @Override public long getWifiOnTime(long batteryRealtime, int which) {
         return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
     }
@@ -3155,6 +3200,8 @@
 
         LongSamplingCounter[] mNetworkByteActivityCounters;
         LongSamplingCounter[] mNetworkPacketActivityCounters;
+        LongSamplingCounter mMobileRadioActiveTime;
+        LongSamplingCounter mMobileRadioActiveCount;
 
         /**
          * The statistics we have collected for this uid's wake locks.
@@ -3555,6 +3602,14 @@
             }
         }
 
+        void noteMobileRadioActiveTimeLocked(long batteryUptime) {
+            if (mNetworkByteActivityCounters == null) {
+                initNetworkActivityLocked();
+            }
+            mMobileRadioActiveTime.addCountLocked(batteryUptime);
+            mMobileRadioActiveCount.addCountLocked(1);
+        }
+
         @Override
         public boolean hasNetworkActivity() {
             return mNetworkByteActivityCounters != null;
@@ -3580,6 +3635,18 @@
             }
         }
 
+        @Override
+        public long getMobileRadioActiveTime(int which) {
+            return mMobileRadioActiveTime != null
+                    ? mMobileRadioActiveTime.getCountLocked(which) : 0;
+        }
+
+        @Override
+        public int getMobileRadioActiveCount(int which) {
+            return mMobileRadioActiveCount != null
+                    ? (int)mMobileRadioActiveCount.getCountLocked(which) : 0;
+        }
+
         void initNetworkActivityLocked() {
             mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
             mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
@@ -3587,6 +3654,8 @@
                 mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
                 mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
             }
+            mMobileRadioActiveTime = new LongSamplingCounter(mUnpluggables);
+            mMobileRadioActiveCount = new LongSamplingCounter(mUnpluggables);
         }
 
         /**
@@ -3651,6 +3720,8 @@
                     mNetworkByteActivityCounters[i].reset(false);
                     mNetworkPacketActivityCounters[i].reset(false);
                 }
+                mMobileRadioActiveTime.reset(false);
+                mMobileRadioActiveCount.reset(false);
             }
 
             if (mWakelockStats.size() > 0) {
@@ -3858,6 +3929,8 @@
                     mNetworkByteActivityCounters[i].writeToParcel(out);
                     mNetworkPacketActivityCounters[i].writeToParcel(out);
                 }
+                mMobileRadioActiveTime.writeToParcel(out);
+                mMobileRadioActiveCount.writeToParcel(out);
             } else {
                 out.writeInt(0);
             }
@@ -3981,6 +4054,8 @@
                     mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
                     mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
                 }
+                mMobileRadioActiveTime = new LongSamplingCounter(mUnpluggables, in);
+                mMobileRadioActiveCount = new LongSamplingCounter(mUnpluggables, in);
             } else {
                 mNetworkByteActivityCounters = null;
                 mNetworkPacketActivityCounters = null;
@@ -5075,6 +5150,9 @@
             mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
         }
         mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mUnpluggables);
+        mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mUnpluggables);
+        mMobileRadioActiveUnknownTime = new LongSamplingCounter(mUnpluggables);
+        mMobileRadioActiveUnknownCount = new LongSamplingCounter(mUnpluggables);
         mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
         mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -5341,6 +5419,9 @@
             mNetworkPacketActivityCounters[i].reset(false);
         }
         mMobileRadioActiveTimer.reset(this, false);
+        mMobileRadioActivePerAppTimer.reset(this, false);
+        mMobileRadioActiveUnknownTime.reset(false);
+        mMobileRadioActiveUnknownCount.reset(false);
         mWifiOnTimer.reset(this, false);
         mGlobalWifiRunningTimer.reset(this, false);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -5418,7 +5499,10 @@
 
     public void pullPendingStateUpdatesLocked() {
         updateKernelWakelocksLocked();
-        updateNetworkActivityLocked();
+        updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
+        if (mOnBatteryInternal) {
+            updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
+        }
     }
 
     void setOnBatteryLocked(boolean onBattery, int oldStatus, int level) {
@@ -5603,10 +5687,14 @@
         }
     }
 
-    private void updateNetworkActivityLocked() {
+    static final int NET_UPDATE_MOBILE = 1<<0;
+    static final int NET_UPDATE_WIFI = 1<<1;
+    static final int NET_UPDATE_ALL = 0xffff;
+
+    private void updateNetworkActivityLocked(int which, long elapsedRealtime) {
         if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
 
-        if (mMobileIfaces.length > 0) {
+        if ((which&NET_UPDATE_MOBILE) != 0 && mMobileIfaces.length > 0) {
             final NetworkStats snapshot;
             final NetworkStats last = mCurMobileSnapshot;
             try {
@@ -5620,32 +5708,57 @@
             mCurMobileSnapshot = snapshot;
             mLastMobileSnapshot = last;
 
-            final NetworkStats delta = NetworkStats.subtract(snapshot, last,
-                    null, null, mTmpNetworkStats);
-            mTmpNetworkStats = delta;
+            if (mOnBatteryInternal) {
+                final NetworkStats delta = NetworkStats.subtract(snapshot, last,
+                        null, null, mTmpNetworkStats);
+                mTmpNetworkStats = delta;
 
-            final int size = delta.size();
-            for (int i = 0; i < size; i++) {
-                final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+                long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(this,
+                        elapsedRealtime);
+                long totalPackets = delta.getTotalPackets();
 
-                if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
+                final int size = delta.size();
+                for (int i = 0; i < size; i++) {
+                    final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
 
-                final Uid u = getUidStatsLocked(entry.uid);
-                u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
-                        entry.rxPackets);
-                u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
-                        entry.txPackets);
+                    if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
 
-                mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(entry.rxBytes);
-                mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(entry.txBytes);
-                mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
-                        entry.rxPackets);
-                mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
-                        entry.txPackets);
+                    final Uid u = getUidStatsLocked(entry.uid);
+                    u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
+                            entry.rxPackets);
+                    u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
+                            entry.txPackets);
+
+                    if (radioTime > 0) {
+                        // Distribute total radio active time in to this app.
+                        long appPackets = entry.rxPackets + entry.txPackets;
+                        long appRadioTime = (radioTime*appPackets)/totalPackets;
+                        u.noteMobileRadioActiveTimeLocked(appRadioTime);
+                        // Remove this app from the totals, so that we don't lose any time
+                        // due to rounding.
+                        radioTime -= appRadioTime;
+                        totalPackets -= appPackets;
+                    }
+
+                    mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
+                            entry.rxBytes);
+                    mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
+                            entry.txBytes);
+                    mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
+                            entry.rxPackets);
+                    mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
+                            entry.txPackets);
+                }
+
+                if (radioTime > 0) {
+                    // Whoops, there is some radio time we can't blame on an app!
+                    mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
+                    mMobileRadioActiveUnknownCount.addCountLocked(1);
+                }
             }
         }
 
-        if (mWifiIfaces.length > 0) {
+        if ((which&NET_UPDATE_WIFI) != 0 && mWifiIfaces.length > 0) {
             final NetworkStats snapshot;
             final NetworkStats last = mCurWifiSnapshot;
             try {
@@ -5659,34 +5772,39 @@
             mCurWifiSnapshot = snapshot;
             mLastWifiSnapshot = last;
 
-            final NetworkStats delta = NetworkStats.subtract(snapshot, last,
-                    null, null, mTmpNetworkStats);
-            mTmpNetworkStats = delta;
-            mLastWifiSnapshot = snapshot;
+            if (mOnBatteryInternal) {
+                final NetworkStats delta = NetworkStats.subtract(snapshot, last,
+                        null, null, mTmpNetworkStats);
+                mTmpNetworkStats = delta;
 
-            final int size = delta.size();
-            for (int i = 0; i < size; i++) {
-                final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+                final int size = delta.size();
+                for (int i = 0; i < size; i++) {
+                    final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
 
-                if (DEBUG) {
-                    final NetworkStats.Entry cur = snapshot.getValues(i, null);
-                    Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
-                            + " tx=" + entry.txBytes + ", cur rx=" + cur.rxBytes
-                            + " tx=" + cur.txBytes);
+                    if (DEBUG) {
+                        final NetworkStats.Entry cur = snapshot.getValues(i, null);
+                        Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
+                                + " tx=" + entry.txBytes + ", cur rx=" + cur.rxBytes
+                                + " tx=" + cur.txBytes);
+                    }
+
+                    if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
+
+                    final Uid u = getUidStatsLocked(entry.uid);
+                    u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
+                            entry.rxPackets);
+                    u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
+                            entry.txPackets);
+
+                    mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+                            entry.rxBytes);
+                    mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+                            entry.txBytes);
+                    mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+                            entry.rxPackets);
+                    mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+                            entry.txPackets);
                 }
-
-                if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
-
-                final Uid u = getUidStatsLocked(entry.uid);
-                u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes, entry.rxPackets);
-                u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes, entry.txPackets);
-
-                mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(entry.rxBytes);
-                mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(entry.txBytes);
-                mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
-                        entry.rxPackets);
-                mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
-                        entry.txPackets);
             }
         }
     }
@@ -6275,6 +6393,9 @@
         }
         mMobileRadioActive = false;
         mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
+        mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
+        mMobileRadioActiveUnknownTime.readSummaryFromParcelLocked(in);
+        mMobileRadioActiveUnknownCount.readSummaryFromParcelLocked(in);
         mWifiOn = false;
         mWifiOnTimer.readSummaryFromParcelLocked(in);
         mGlobalWifiRunning = false;
@@ -6370,6 +6491,8 @@
                     u.mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
                     u.mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
                 }
+                u.mMobileRadioActiveTime.readSummaryFromParcelLocked(in);
+                u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in);
             }
 
             int NW = in.readInt();
@@ -6506,6 +6629,9 @@
             mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
         }
         mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+        mMobileRadioActiveUnknownTime.writeSummaryFromParcelLocked(out);
+        mMobileRadioActiveUnknownCount.writeSummaryFromParcelLocked(out);
         mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
@@ -6609,6 +6735,8 @@
                     u.mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
                     u.mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
                 }
+                u.mMobileRadioActiveTime.writeSummaryFromParcelLocked(out);
+                u.mMobileRadioActiveCount.writeSummaryFromParcelLocked(out);
             }
 
             int NW = u.mWakelockStats.size();
@@ -6748,6 +6876,9 @@
         }
         mMobileRadioActive = false;
         mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mUnpluggables, in);
+        mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mUnpluggables, in);
+        mMobileRadioActiveUnknownTime = new LongSamplingCounter(mUnpluggables, in);
+        mMobileRadioActiveUnknownCount = new LongSamplingCounter(mUnpluggables, in);
         mWifiOn = false;
         mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
         mGlobalWifiRunning = false;
@@ -6865,6 +6996,9 @@
             mNetworkPacketActivityCounters[i].writeToParcel(out);
         }
         mMobileRadioActiveTimer.writeToParcel(out, batteryRealtime);
+        mMobileRadioActivePerAppTimer.writeToParcel(out, batteryRealtime);
+        mMobileRadioActiveUnknownTime.writeToParcel(out);
+        mMobileRadioActiveUnknownCount.writeToParcel(out);
         mWifiOnTimer.writeToParcel(out, batteryRealtime);
         mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index bf62745..05c57e8 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -244,9 +244,11 @@
     }
 
     static void preload() {
+        Log.d(TAG, "begin preload");
         preloadClasses();
         preloadResources();
         preloadOpenGL();
+        Log.d(TAG, "end preload");
     }
 
     private static void preloadOpenGL() {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 5056c57..a09c314 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -164,9 +164,8 @@
 	$(TOP)/frameworks/av/include \
 	$(TOP)/system/media/camera/include \
 	external/skia/src/core \
-	external/skia/src/pdf \
+	external/skia/src/effects \
 	external/skia/src/images \
-	external/skia/include/utils \
 	external/sqlite/dist \
 	external/sqlite/android \
 	external/expat/lib \
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index f331af7..5573366 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -1,5 +1,6 @@
 #include "GraphicsJNI.h"
 #include "SkMaskFilter.h"
+#include "SkBlurMask.h"
 #include "SkBlurMaskFilter.h"
 #include "SkTableMaskFilter.h"
 
@@ -19,8 +20,9 @@
     }
 
     static jlong createBlur(JNIEnv* env, jobject, jfloat radius, jint blurStyle) {
-        SkMaskFilter* filter = SkBlurMaskFilter::Create(SkFloatToScalar(radius),
-                                        (SkBlurMaskFilter::BlurStyle)blurStyle);
+        SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(SkFloatToScalar(radius));
+        SkMaskFilter* filter = SkBlurMaskFilter::Create(
+                (SkBlurMaskFilter::BlurStyle)blurStyle, sigma);
         ThrowIAE_IfNull(env, filter);
         return reinterpret_cast<jlong>(filter);
     }
@@ -34,10 +36,9 @@
             direction[i] = SkFloatToScalar(values[i]);
         }
 
-        SkMaskFilter* filter =  SkBlurMaskFilter::CreateEmboss(direction,
-                                                      SkFloatToScalar(ambient),
-                                                      SkFloatToScalar(specular),
-                                                      SkFloatToScalar(radius));
+        SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(SkFloatToScalar(radius));
+        SkMaskFilter* filter =  SkBlurMaskFilter::CreateEmboss(sigma,
+                direction, SkFloatToScalar(ambient), SkFloatToScalar(specular));
         ThrowIAE_IfNull(env, filter);
         return reinterpret_cast<jlong>(filter);
     }
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 6bbf45a..429f177 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -25,7 +25,7 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include "SkPath.h"
-#include "pathops/SkPathOps.h"
+#include "SkPathOps.h"
 
 #include <Caches.h>
 #include <vector>
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 3047440..1fe6358 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -520,7 +520,7 @@
     SkiaShader* shaderB = reinterpret_cast<SkiaShader *>(shaderBHandle);
     SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
     SkXfermode::Mode skiaMode;
-    if (!SkXfermode::IsMode(mode, &skiaMode)) {
+    if (!SkXfermode::AsMode(mode, &skiaMode)) {
         // TODO: Support other modes
         skiaMode = SkXfermode::kSrcOver_Mode;
     }
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index a17f328..a91c622 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -27,7 +27,7 @@
 #include <GLES/gl.h>
 #include <ETC1/etc1.h>
 
-#include <core/SkBitmap.h>
+#include <SkBitmap.h>
 
 #include "android_runtime/AndroidRuntime.h"
 
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index c10b963f..467a9a1 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -123,20 +123,45 @@
     return (ret == 0) ? JNI_TRUE : JNI_FALSE;
 }
 
-static jint
+static jboolean
 android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, jint interfaceID)
 {
     struct usb_device* device = get_device_from_object(env, thiz);
     if (!device) {
         ALOGE("device is closed in native_release_interface");
-        return -1;
+        return JNI_FALSE;
     }
     int ret = usb_device_release_interface(device, interfaceID);
     if (ret == 0) {
         // allow kernel to reconnect its driver
         usb_device_connect_kernel_driver(device, interfaceID, true);
     }
-    return ret;
+    return (ret == 0) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean
+android_hardware_UsbDeviceConnection_set_interface(JNIEnv *env, jobject thiz, jint interfaceID,
+        jint alternateSetting)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        ALOGE("device is closed in native_set_interface");
+        return JNI_FALSE;
+    }
+    int ret = usb_device_set_interface(device, interfaceID, alternateSetting);
+    return (ret == 0) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean
+android_hardware_UsbDeviceConnection_set_configuration(JNIEnv *env, jobject thiz, jint configurationID)
+{
+    struct usb_device* device = get_device_from_object(env, thiz);
+    if (!device) {
+        ALOGE("device is closed in native_set_configuration");
+        return JNI_FALSE;
+    }
+    int ret = usb_device_set_configuration(device, configurationID);
+    return (ret == 0) ? JNI_TRUE : JNI_FALSE;
 }
 
 static jint
@@ -229,6 +254,8 @@
     {"native_get_desc",         "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc},
     {"native_claim_interface",  "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},
     {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},
+    {"native_set_interface","(II)Z",    (void *)android_hardware_UsbDeviceConnection_set_interface},
+    {"native_set_configuration","(I)Z", (void *)android_hardware_UsbDeviceConnection_set_configuration},
     {"native_control_request",  "(IIII[BIII)I",
                                         (void *)android_hardware_UsbDeviceConnection_control_request},
     {"native_bulk_request",     "(I[BIII)I",
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 9c357de..0132b5f 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -18,6 +18,7 @@
 
 #define LOG_TAG "AudioRecord-JNI"
 
+#include <inttypes.h>
 #include <jni.h>
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
@@ -311,7 +312,7 @@
     if (lpRecorder == NULL) {
         return;
     }
-    ALOGV("About to delete lpRecorder: %x\n", (int)lpRecorder.get());
+    ALOGV("About to delete lpRecorder: %" PRIxPTR "\n", lpRecorder.get());
     lpRecorder->stop();
 
     audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
@@ -324,7 +325,7 @@
     // delete the callback information
     if (lpCookie) {
         Mutex::Autolock l(sLock);
-        ALOGV("deleting lpCookie: %x\n", (int)lpCookie);
+        ALOGV("deleting lpCookie: %" PRIxPTR "\n", lpCookie);
         while (lpCookie->busy) {
             if (lpCookie->cond.waitRelative(sLock,
                                             milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 8c7b34a..7e958e7 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -263,7 +263,7 @@
 
     // compute the frame count
     const size_t bytesPerSample = audio_bytes_per_sample(format);
-    int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
+    size_t frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
 
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index bf65dfc..19e4d99 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -156,7 +156,7 @@
 android_eglGetDisplayInt
   (JNIEnv *_env, jobject _this, jint display_id) {
 
-    if (sizeof(void*) != sizeof(uint32_t)) {
+    if ((EGLNativeDisplayType)display_id != EGL_DEFAULT_DISPLAY) {
         jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay");
         return 0;
     }
diff --git a/core/res/res/layout-xlarge/screen_action_bar.xml b/core/res/res/layout-xlarge/screen_action_bar.xml
index e495e53..d2fe9fa 100644
--- a/core/res/res/layout-xlarge/screen_action_bar.xml
+++ b/core/res/res/layout-xlarge/screen_action_bar.xml
@@ -34,6 +34,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentTop="true"
         style="?android:attr/actionBarStyle"
+        android:sharedElementName="android:action_bar"
         android:gravity="top">
         <com.android.internal.widget.ActionBarView
             android:id="@+id/action_bar"
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index b1889a2..7b9a20b 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -33,6 +33,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentTop="true"
         style="?android:attr/actionBarStyle"
+        android:sharedElementName="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 e3364d1..d02cc8b 100644
--- a/core/res/res/layout/screen_custom_title.xml
+++ b/core/res/res/layout/screen_custom_title.xml
@@ -31,6 +31,7 @@
     <FrameLayout android:id="@android:id/title_container" 
         android:layout_width="match_parent" 
         android:layout_height="?android:attr/windowTitleSize"
+        android:sharedElementName="android:title"
         style="?android:attr/windowTitleBackgroundStyle">
     </FrameLayout>
     <FrameLayout android:id="@android:id/content"
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 4f38a82..9156057 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -46,7 +46,7 @@
     <string name="badPin" msgid="9015277645546710014">"የተየበከው የድሮ ፒን ትክክል አይደለም።"</string>
     <string name="badPuk" msgid="5487257647081132201">"የተየብከው PUK ትክክል  አይደለም።"</string>
     <string name="mismatchPin" msgid="609379054496863419">"ያስገባሃቸው ፒኖች አይዛመዱም"</string>
-    <string name="invalidPin" msgid="3850018445187475377">"ከ4 እስከ 8 ቁጥሮች የያዘ PIN ተይብ"</string>
+    <string name="invalidPin" msgid="3850018445187475377">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን  ተይብ"</string>
     <string name="invalidPuk" msgid="8761456210898036513">"8 ወይም ከዛ በላይ የሆኑ ቁጥሮችንPUK ተይብ።"</string>
     <string name="needPuk" msgid="919668385956251611">"SIM ካርድዎ PUK-የተቆለፈ ነው።የPUK ኮዱን በመተየብ ይክፈቱት።"</string>
     <string name="needPuk2" msgid="4526033371987193070">" SIM ለመክፈት PUK2 ተይብ።"</string>
@@ -832,7 +832,7 @@
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"የይለፍ ቃል ለመተየብ ንካ"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ለመክፈት የይለፍ ቃል ተይብ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ለመክፈት ፒን ተይብ"</string>
-    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ PIN ኮድ።"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ ፒን  ኮድ።"</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"ለመክፈት፣ምናሌ ተጫን ከዛ 0"</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"የአደጋ ጊዜቁጥር"</string>
     <string name="lockscreen_carrier_default" msgid="8963839242565653192">"ከአገልግሎት መስጫ ክልል ውጪ"</string>
@@ -994,8 +994,8 @@
     <string name="searchview_description_submit" msgid="2688450133297983542">"ጥያቄ አስረክብ"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"የድምፅ ፍለጋ"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"በመንካት አስስ ይንቃ?"</string>
-    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>  ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከጡባዊ ተኮው ጋር ለመግባባት ምን በጣትህ ስር ወይም ምልክቶችን ማከናወን እንዳለብህ ማብራሪያ ልታይ ወይም ልትሰማ ትችላለህ።"</string>
-    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>  ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከስልኩ ጋር ለመግባባት ምን በጣትህ ስር ወይም ምልክቶችን ማከናወን እንዳለብህ ማብራሪያ ልታይ ወይም ልትሰማ ትችላለህ።"</string>
+    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>  ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከጡባዊ ተኮው ጋር ለመግባባት ምን በጣትዎ ስር ወይም ምልክቶችን ማከናወን እንዳለብዎ ማብራሪያ ሊመለከቱ ወይም ሊሰሙ ይችላሉ።"</string>
+    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>  ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከስልኩ ጋር ለመግባባት ምን በጣትዎ ስር ወይም ምልክቶችን ማከናወን እንዳለብዎ ማብራሪያ ሊመለከቱ ወይም ሊሰሙ ይችላሉ።"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
   <plurals name="num_seconds_ago">
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 50c7187..cde9bdf 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -683,8 +683,8 @@
     <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permet que l\'aplicació modifiqui les marques de sòcols per a l\'encaminament"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
-    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei de processament de notificacions"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei de processament de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei oient de notificacions"</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei oient de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoca l\'aplicació de configuració proporcionada per l\'operador"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet que el titular invoqui l\'aplicació de configuració proporcionada per l\'operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"conèixer les observacions sobre les condicions de la xarxa"</string>
@@ -1346,7 +1346,7 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilitat"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fons de pantalla"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Canvia el fons de pantalla"</string>
-    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Processador de notificacions"</string>
+    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Oient de notificacions"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ha activat VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca per gestionar la xarxa."</string>
diff --git a/core/res/res/values-mcc440-mnc20/config.xml b/core/res/res/values-mcc440-mnc20/config.xml
index ba709fa..62001d9 100644
--- a/core/res/res/values-mcc440-mnc20/config.xml
+++ b/core/res/res/values-mcc440-mnc20/config.xml
@@ -23,6 +23,6 @@
 
     <!-- Configure mobile network MTU. Carrier specific value is set here.
     -->
-    <integer name="config_mobile_mtu">1340</integer>
+    <integer name="config_mobile_mtu">1422</integer>
 
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 1d5772b..d3934a9 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -190,7 +190,7 @@
     <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Prístup k zariadeniam a sieťam prostredníctvom rozhrania Bluetooth."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Nastavenia zvuku"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Zmena nastavení zvuku."</string>
-    <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Má vplyv na batériu"</string>
+    <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Vplyv na batériu"</string>
     <string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Používanie funkcií, ktoré môžu rýchlo vyčerpať batériu."</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendár"</string>
     <string name="permgroupdesc_calendar" msgid="5777534316982184416">"Priamy prístup ku kalendáru a udalostiam."</string>
@@ -232,7 +232,7 @@
     <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"Funkcie len pre vývojárov aplikácií."</string>
     <string name="permgrouplab_display" msgid="4279909676036402636">"Používateľské rozhranie iných aplikácií"</string>
     <string name="permgroupdesc_display" msgid="6051002031933013714">"Vplyv na používateľské rozhranie ďalších aplikácií."</string>
-    <string name="permgrouplab_storage" msgid="1971118770546336966">"Ukladací priestor"</string>
+    <string name="permgrouplab_storage" msgid="1971118770546336966">"Úložisko"</string>
     <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Prístup do ukl. priestoru USB."</string>
     <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Prístup na kartu SD."</string>
     <string name="permgrouplab_accessibilityFeatures" msgid="7919025602283593907">"Funkcie zjednodušenia ovládania"</string>
@@ -566,7 +566,7 @@
     <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čítanie presných stavov telefónu"</string>
     <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Umožňuje aplikácii pristupovať k presným stavom telefónu. Toto povolenie umožňuje aplikácii zistiť skutočný stav hovoru, či je hovor aktívny alebo na pozadí, zlyhania hovorov, presný stav dátového pripojenia a zlyhania dátového pripojenia."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zabránenie prechodu tabletu do režimu spánku"</string>
-    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zabránenie prechodu telefónu do režimu spánku"</string>
+    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"deaktivácia režimu spánku"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikácii zabrániť prechodu tabletu do režimu spánku."</string>
     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Umožňuje aplikácii zabrániť prechodu telefónu do režimu spánku."</string>
     <string name="permlab_transmitIr" msgid="7545858504238530105">"infračervený prenos"</string>
@@ -637,7 +637,7 @@
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Umožňuje aplikácii zobraziť informácie o konfigurácii Bluetooth na telefóne. Taktiež jej umožňuje nadväzovať a akceptovať spojenia so spárovanými zariadeniami."</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"ovládať technológiu Near Field Communication"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"Umožňuje aplikácii komunikovať so značkami, kartami a čítačkami s podporou technológie Near Field Communication (NFC)."</string>
-    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"zakázať uzamknutie obrazovky"</string>
+    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"deaktivácia zámky obrazovky"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Umožňuje aplikácii zakázať uzamknutie klávesnice a akékoľvek súvisiace zabezpečenie heslom. Príkladom je zakázanie uzamknutia klávesnice pri prichádzajúcom telefonickom hovore a jeho opätovné povolenie po skončení hovoru."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čítanie nastavení synchronizácie"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Umožňuje aplikácii čítať nastavenia synchronizácie v účte. Môže napríklad určiť, či je s účtom synchronizovaná aplikácia Ľudia."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index bfd7565..42fa106 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2357,8 +2357,8 @@
         <!-- Sets whether or not this ViewGroup should be treated as a single entity
              when doing an Activity transition. Typically, the elements inside a
              ViewGroup are each transitioned from the scene individually. The default
-             for a ViewGroup is false unless it has a background.
-             See {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)}
+             for a ViewGroup is false unless it has a background. See
+             {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.View, String)}
              for more information. -->
         <attr name="transitionGroup" format="boolean" />
     </declare-styleable>
@@ -4760,14 +4760,6 @@
         <attr name="fromScene" format="reference" />
         <!-- The destination scene in this scene change. -->
         <attr name="toScene" format="reference" />
-        <!-- The name of the originating scene in this scene change.
-             Apps should treat this name as an API in the same sense
-             that an Intent action or extra key is. -->
-        <attr name="fromSceneName" format="string" />
-        <!-- The name of the destination scene in this scene change.
-             Apps should treat this name as an API in the same sense
-             that an Intent action or extra key is. -->
-        <attr name="toSceneName" format="string" />
     </declare-styleable>
 
     <!-- ========================== -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c814d25..3106daa 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2103,8 +2103,6 @@
   <public type="attr" name="controlY1" />
   <public type="attr" name="controlX2" />
   <public type="attr" name="controlY2" />
-  <public type="attr" name="fromSceneName" />
-  <public type="attr" name="toSceneName" />
   <public type="attr" name="sharedElementName" />
   <public type="attr" name="transitionGroup" />
   <public type="attr" name="castsShadow" />
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
new file mode 100644
index 0000000..9f04228
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -0,0 +1,41 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := 9
+
+LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v1
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+
+mainDexList:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+
+include $(BUILD_PACKAGE)
+
+$(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
+	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
new file mode 100644
index 0000000..c7b066d
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.framework.multidexlegacyversionedtestapp"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="9"
+        android:targetSdkVersion="18" />
+
+    <application
+        android:name="android.support.multidex.MultiDexApplication"
+        android:allowBackup="true"
+        android:label="MultiDexLegacyVersionedTestApp_v1">
+        <activity
+            android:name="com.android.framework.multidexlegacyversionedtestapp.MainActivity"
+            android:label="MultiDexLegacyVersionedTestApp_v1" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.multidexlegacyversionedtestapp"
+                     android:label="Test for MultiDexLegacyVersionedTestApp_v1" />
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/res/layout/activity_main.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/res/layout/activity_main.xml
new file mode 100644
index 0000000..58ae67a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/res/layout/activity_main.xml
@@ -0,0 +1,7 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity" >
+
+</RelativeLayout>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
new file mode 100644
index 0000000..8662562
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
@@ -0,0 +1,29 @@
+/*
+ * 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.framework.multidexlegacyversionedtestapp;
+
+/**
+ * Class directly referenced from Activity, will be kept in main dex. The class is not referenced
+ * by <clinit> or <init>, its direct references are not kept in main dex.
+ */
+public class ClassForMainDex {
+
+    public static int getVersion() {
+        return Version.getVersion();
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
new file mode 100644
index 0000000..351d860
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
@@ -0,0 +1,34 @@
+/*
+ * 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.framework.multidexlegacyversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+    }
+
+    public int getVersion() {
+        return ClassForMainDex.getVersion();
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
new file mode 100644
index 0000000..24b4d69
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.framework.multidexlegacyversionedtestapp;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ com.android.framework.multidexlegacyversionedtestapp/android.test.InstrumentationTestRunner
+</code>
+ */
+public class MultiDexUpdateTest extends ActivityInstrumentationTestCase2<MainActivity>
+{
+    public MultiDexUpdateTest() {
+        super(MainActivity.class);
+    }
+
+    /**
+     * Tests that all classes of the application can be loaded. Verifies also that we load the
+     * correct version of {@link Version} ie the class is the secondary dex file.
+     */
+    public void testAllClassAvailable()
+    {
+        assertEquals(1, getActivity().getVersion());
+    }
+}
diff --git a/media/java/android/media/IMediaControllerCallback.aidl b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
similarity index 61%
copy from media/java/android/media/IMediaControllerCallback.aidl
copy to core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
index b54d0cf..eb9827a 100644
--- a/media/java/android/media/IMediaControllerCallback.aidl
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014 The Android Open Source Project
+/*
+ * 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.
@@ -13,16 +14,12 @@
  * limitations under the License.
  */
 
-package android.media;
+package com.android.framework.multidexlegacyversionedtestapp;
 
-import android.os.Bundle;
+/* can go in secondary dex */
+public class Version {
 
-/**
- * @hide
- */
-oneway interface IMediaControllerCallback {
-    void onEvent(String event, in Bundle extras);
-    void onMetadataUpdate(in Bundle metadata);
-    void onPlaybackUpdate(int newState);
-    void onRouteChanged(in Bundle route);
-}
\ No newline at end of file
+    public static int getVersion() {
+        return 1;
+    }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
new file mode 100644
index 0000000..1b8da41
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -0,0 +1,41 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := 9
+
+LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v2
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+
+mainDexList:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+
+include $(BUILD_PACKAGE)
+
+$(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
+	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
new file mode 100644
index 0000000..4d24793
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.framework.multidexlegacyversionedtestapp"
+    android:versionCode="2"
+    android:versionName="2.0" >
+
+    <uses-sdk
+        android:minSdkVersion="9"
+        android:targetSdkVersion="18" />
+
+    <application
+        android:name="android.support.multidex.MultiDexApplication"
+        android:allowBackup="true"
+        android:label="MultiDexLegacyVersionedTestApp_v2">
+        <activity
+            android:name="com.android.framework.multidexlegacyversionedtestapp.MainActivity"
+            android:label="MultiDexLegacyVersionedTestApp_v2" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.multidexlegacyversionedtestapp"
+                     android:label="Test for MultiDexLegacyVersionedTestApp_v2" />
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/res/layout/activity_main.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/res/layout/activity_main.xml
new file mode 100644
index 0000000..58ae67a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/res/layout/activity_main.xml
@@ -0,0 +1,7 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity" >
+
+</RelativeLayout>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
new file mode 100644
index 0000000..8662562
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
@@ -0,0 +1,29 @@
+/*
+ * 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.framework.multidexlegacyversionedtestapp;
+
+/**
+ * Class directly referenced from Activity, will be kept in main dex. The class is not referenced
+ * by <clinit> or <init>, its direct references are not kept in main dex.
+ */
+public class ClassForMainDex {
+
+    public static int getVersion() {
+        return Version.getVersion();
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
new file mode 100644
index 0000000..351d860
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
@@ -0,0 +1,34 @@
+/*
+ * 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.framework.multidexlegacyversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+    }
+
+    public int getVersion() {
+        return ClassForMainDex.getVersion();
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
new file mode 100644
index 0000000..f130cb2
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.framework.multidexlegacyversionedtestapp;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ com.android.framework.multidexlegacyversionedtestapp/android.test.InstrumentationTestRunner
+</code>
+ */
+public class MultiDexUpdateTest extends ActivityInstrumentationTestCase2<MainActivity>
+{
+    public MultiDexUpdateTest() {
+        super(MainActivity.class);
+    }
+
+    /**
+     * Tests that all classes of the application can be loaded. Verifies also that we load the
+     * correct version of {@link Version} ie the class is the secondary dex file.
+     */
+    public void testAllClassAvailable()
+    {
+        assertEquals(2, getActivity().getVersion());
+    }
+}
diff --git a/media/java/android/media/IMediaControllerCallback.aidl b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
similarity index 61%
copy from media/java/android/media/IMediaControllerCallback.aidl
copy to core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
index b54d0cf..1f2305f 100644
--- a/media/java/android/media/IMediaControllerCallback.aidl
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014 The Android Open Source Project
+/*
+ * 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.
@@ -13,16 +14,12 @@
  * limitations under the License.
  */
 
-package android.media;
+package com.android.framework.multidexlegacyversionedtestapp;
 
-import android.os.Bundle;
+/* can go in secondary dex */
+public class Version {
 
-/**
- * @hide
- */
-oneway interface IMediaControllerCallback {
-    void onEvent(String event, in Bundle extras);
-    void onMetadataUpdate(in Bundle metadata);
-    void onPlaybackUpdate(int newState);
-    void onRouteChanged(in Bundle route);
-}
\ No newline at end of file
+    public static int getVersion() {
+        return 2;
+    }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
new file mode 100644
index 0000000..945bfcca
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -0,0 +1,41 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := 9
+
+LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v3
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+
+mainDexList:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+
+include $(BUILD_PACKAGE)
+
+$(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
+	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
new file mode 100644
index 0000000..76c92dd
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.framework.multidexlegacyversionedtestapp"
+    android:versionCode="3"
+    android:versionName="3.0" >
+
+    <uses-sdk
+        android:minSdkVersion="9"
+        android:targetSdkVersion="18" />
+
+    <application
+        android:name="android.support.multidex.MultiDexApplication"
+        android:allowBackup="true"
+        android:label="MultiDexLegacyVersionedTestApp_v3">
+        <activity
+            android:name="com.android.framework.multidexlegacyversionedtestapp.MainActivity"
+            android:label="MultiDexLegacyVersionedTestApp_v3" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.framework.multidexlegacyversionedtestapp"
+                     android:label="Test for MultiDexLegacyVersionedTestApp_v3" />
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/res/layout/activity_main.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/res/layout/activity_main.xml
new file mode 100644
index 0000000..58ae67a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/res/layout/activity_main.xml
@@ -0,0 +1,7 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity" >
+
+</RelativeLayout>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
new file mode 100644
index 0000000..8662562
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
@@ -0,0 +1,29 @@
+/*
+ * 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.framework.multidexlegacyversionedtestapp;
+
+/**
+ * Class directly referenced from Activity, will be kept in main dex. The class is not referenced
+ * by <clinit> or <init>, its direct references are not kept in main dex.
+ */
+public class ClassForMainDex {
+
+    public static int getVersion() {
+        return Version.getVersion();
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
new file mode 100644
index 0000000..351d860
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
@@ -0,0 +1,34 @@
+/*
+ * 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.framework.multidexlegacyversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+    }
+
+    public int getVersion() {
+        return ClassForMainDex.getVersion();
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
new file mode 100644
index 0000000..67aa478
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.framework.multidexlegacyversionedtestapp;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ com.android.framework.multidexlegacyversionedtestapp/android.test.InstrumentationTestRunner
+</code>
+ */
+public class MultiDexUpdateTest extends ActivityInstrumentationTestCase2<MainActivity>
+{
+    public MultiDexUpdateTest() {
+        super(MainActivity.class);
+    }
+
+    /**
+     * Tests that all classes of the application can be loaded. Verifies also that we load the
+     * correct version of {@link Version} ie the class is the secondary dex file.
+     */
+    public void testAllClassAvailable()
+    {
+        assertEquals(3, getActivity().getVersion());
+    }
+}
diff --git a/media/java/android/media/IMediaControllerCallback.aidl b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
similarity index 61%
copy from media/java/android/media/IMediaControllerCallback.aidl
copy to core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
index b54d0cf..1c8ef3b 100644
--- a/media/java/android/media/IMediaControllerCallback.aidl
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014 The Android Open Source Project
+/*
+ * 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.
@@ -13,16 +14,12 @@
  * limitations under the License.
  */
 
-package android.media;
+package com.android.framework.multidexlegacyversionedtestapp;
 
-import android.os.Bundle;
+/* can go in secondary dex */
+public class Version {
 
-/**
- * @hide
- */
-oneway interface IMediaControllerCallback {
-    void onEvent(String event, in Bundle extras);
-    void onMetadataUpdate(in Bundle metadata);
-    void onPlaybackUpdate(int newState);
-    void onRouteChanged(in Bundle route);
-}
\ No newline at end of file
+    public static int getVersion() {
+        return 3;
+    }
+}
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
index 0a2b50c..fa1bd8f 100644
--- a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
@@ -34,6 +34,7 @@
     private static final boolean IS_AUX = true;
     private static final boolean IS_DEFAULT = true;
     private static final boolean IS_AUTO = true;
+    private static final ArrayList<InputMethodSubtype> NO_SUBTYPE = null;
 
     @SmallTest
     public void testDefaultEnabledImesWithDefaultVoiceIme() throws Exception {
@@ -45,6 +46,7 @@
         imis.add(createNonDefaultDummyVoiceIme2());
         imis.add(createDefaultDummyEnUSKeyboardIme());
         imis.add(createNonDefaultDummyJaJPKeyboardIme());
+        imis.add(createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes());
         final ArrayList<InputMethodInfo> enabledImis = InputMethodUtils.getDefaultEnabledImes(
                 context, true, imis);
         assertEquals(2, enabledImis.size());
@@ -69,6 +71,7 @@
         imis.add(createNonDefaultDummyVoiceIme2());
         imis.add(createDefaultDummyEnUSKeyboardIme());
         imis.add(createNonDefaultDummyJaJPKeyboardIme());
+        imis.add(createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes());
         final ArrayList<InputMethodInfo> enabledImis = InputMethodUtils.getDefaultEnabledImes(
                 context, true, imis);
         assertEquals(3, enabledImis.size());
@@ -86,6 +89,55 @@
         }
     }
 
+    @SmallTest
+    public void testParcelable() throws Exception {
+        final ArrayList<InputMethodInfo> originalList = new ArrayList<InputMethodInfo>();
+        originalList.add(createNonDefaultAutoDummyVoiceIme0());
+        originalList.add(createNonDefaultAutoDummyVoiceIme1());
+        originalList.add(createNonDefaultDummyVoiceIme2());
+        originalList.add(createDefaultDummyEnUSKeyboardIme());
+        originalList.add(createNonDefaultDummyJaJPKeyboardIme());
+        originalList.add(createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes());
+
+        final List<InputMethodInfo> clonedList = cloneViaParcel(originalList);
+        assertNotNull(clonedList);
+        final List<InputMethodInfo> clonedClonedList = cloneViaParcel(clonedList);
+        assertNotNull(clonedClonedList);
+        assertEquals(originalList, clonedList);
+        assertEquals(clonedList, clonedClonedList);
+        assertEquals(originalList.size(), clonedList.size());
+        assertEquals(clonedList.size(), clonedClonedList.size());
+        for (int imeIndex = 0; imeIndex < originalList.size(); ++imeIndex) {
+            verifyEquality(originalList.get(imeIndex), clonedList.get(imeIndex));
+            verifyEquality(clonedList.get(imeIndex), clonedClonedList.get(imeIndex));
+        }
+    }
+
+    private static List<InputMethodInfo> cloneViaParcel(final List<InputMethodInfo> list) {
+        Parcel p = null;
+        try {
+            p = Parcel.obtain();
+            p.writeTypedList(list);
+            p.setDataPosition(0);
+            return p.createTypedArrayList(InputMethodInfo.CREATOR);
+        } finally {
+            if (p != null) {
+                p.recycle();
+            }
+        }
+    }
+
+    private static void verifyEquality(InputMethodInfo expected, InputMethodInfo actual) {
+        assertEquals(expected, actual);
+        assertEquals(expected.getSubtypeCount(), actual.getSubtypeCount());
+        for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) {
+            final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex);
+            final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex);
+            assertEquals(expectedSubtype, actualSubtype);
+            assertEquals(expectedSubtype.hashCode(), actualSubtype.hashCode());
+        }
+    }
+
     private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
             CharSequence label, boolean isAuxIme, boolean isDefault,
             List<InputMethodSubtype> subtypes) {
@@ -155,4 +207,12 @@
         return createDummyInputMethodInfo("DummyNonDefaultJaJPKeyboardIme", "dummy.keyboard1",
                 "DummyKeyboard1", !IS_AUX, !IS_DEFAULT, subtypes);
     }
+
+    // Although IMEs that have no subtype are considered to be deprecated, the Android framework
+    // must still be able to handle such IMEs as well as IMEs that have at least one subtype.
+    private static InputMethodInfo createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes() {
+        final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        return createDummyInputMethodInfo("DummyNonDefaultJaJPKeyboardImeWithoutSubtypes",
+                "dummy.keyboard2", "DummyKeyboard2", !IS_AUX, !IS_DEFAULT, NO_SUBTYPE);
+    }
 }
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 2f4196a..fe08f4b 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -27,10 +27,8 @@
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.GradientDrawable.GradientState;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.Xfermode;
@@ -558,6 +556,11 @@
         invalidateSelf();
     }
 
+    @Override
+    public ColorFilter getColorFilter() {
+        return mBitmapState.mPaint.getColorFilter();
+    }
+
     /**
      * Specifies a tint for this drawable.
      * <p>
@@ -568,31 +571,63 @@
      *            clear the tint
      */
     public void setTint(ColorStateList tint) {
-        mBitmapState.mTint = tint;
-        if (mTintFilter == null) {
-            if (tint != null) {
-                final int color = tint.getColorForState(getState(), 0);
-                mTintFilter = new PorterDuffColorFilter(color, mBitmapState.mTintMode);
-            }
-        } else {
-            if (tint == null) {
-                mTintFilter = null;
-            }
+        if (mBitmapState.mTint != tint) {
+            mBitmapState.mTint = tint;
+            updateTintFilter();
+            invalidateSelf();
         }
-        invalidateSelf();
+    }
+
+    /**
+     * Returns the tint color for this drawable.
+     *
+     * @return Color state list to use for tinting this drawable, or null if
+     *         none set
+     */
+    public ColorStateList getTint() {
+        return mBitmapState.mTint;
     }
 
     /**
      * Specifies the blending mode used to apply tint.
      *
      * @param tintMode A Porter-Duff blending mode
+     * @hide Pending finalization of supported Modes
      */
     public void setTintMode(Mode tintMode) {
-        mBitmapState.mTintMode = tintMode;
-        if (mTintFilter != null) {
-            mTintFilter.setMode(tintMode);
+        if (mBitmapState.mTintMode != tintMode) {
+            mBitmapState.mTintMode = tintMode;
+            updateTintFilter();
+            invalidateSelf();
         }
-        invalidateSelf();
+    }
+
+    /**
+     * Returns the tint mode for this drawable, or {@code null} if none set.
+     *
+     * @return the tint mode for this drawable, or {@code null} if none set
+     * @hide
+     */
+    public Mode getTintMode() {
+        return mBitmapState.mTintMode;
+    }
+
+    /**
+     * Ensures the tint filter is consistent with the current tint color and
+     * mode.
+     */
+    private void updateTintFilter() {
+        final ColorStateList tint = mBitmapState.mTint;
+        final Mode tintMode = mBitmapState.mTintMode;
+        if (tint != null && tintMode != null) {
+            if (mTintFilter == null) {
+                mTintFilter = new PorterDuffColorFilter(0, tintMode);
+            } else {
+                mTintFilter.setMode(tintMode);
+            }
+        } else {
+            mTintFilter = null;
+        }
     }
 
     /**
@@ -730,7 +765,7 @@
     final static class BitmapState extends ConstantState {
         Bitmap mBitmap;
         ColorStateList mTint;
-        Mode mTintMode;
+        Mode mTintMode = Mode.SRC_IN;
         int mChangingConfigurations;
         int mGravity = Gravity.FILL;
         Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index a9cf115..84211ef 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -454,12 +454,6 @@
     }
 
     /**
-     * Specify an optional color filter for the drawable. Pass null to remove
-     * any existing color filter.
-     */
-    public abstract void setColorFilter(ColorFilter cf);
-
-    /**
      * @hide Consider for future API inclusion
      */
     public void setXfermode(Xfermode mode) {
@@ -469,6 +463,15 @@
     }
 
     /**
+     * Specify an optional color filter for the drawable. Pass {@code null} to
+     * remove any existing color filter.
+     *
+     * @param cf the color filter to apply, or {@code null} to remove the
+     *            existing color filter
+     */
+    public abstract void setColorFilter(ColorFilter cf);
+
+    /**
      * Specify a color and Porter-Duff mode to be the color filter for this
      * drawable.
      */
@@ -477,6 +480,15 @@
     }
 
     /**
+     * Returns the current color filter, or {@code null} if none set.
+     *
+     * @return the current color filter, or {@code null} if none set
+     */
+    public ColorFilter getColorFilter() {
+        return null;
+    }
+
+    /**
      * Removes the color filter for this drawable.
      */
     public void clearColorFilter() {
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index aab1fd9..44584a7 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -27,11 +27,10 @@
 import android.graphics.NinePatch;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.drawable.BitmapDrawable.BitmapState;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
@@ -327,31 +326,53 @@
      *            clear the tint
      */
     public void setTint(ColorStateList tint) {
-        mNinePatchState.mTint = tint;
-        if (mTintFilter == null) {
-            if (tint != null) {
-                final int color = tint.getColorForState(getState(), 0);
-                mTintFilter = new PorterDuffColorFilter(color, mNinePatchState.mTintMode);
-            }
-        } else {
-            if (tint == null) {
-                mTintFilter = null;
-            }
+        if (mNinePatchState.mTint != tint) {
+            mNinePatchState.mTint = tint;
+            updateTintFilter();
+            invalidateSelf();
         }
-        invalidateSelf();
+    }
+
+    /**
+     * Returns the tint color for this drawable.
+     *
+     * @return Color state list to use for tinting this drawable, or null if
+     *         none set
+     */
+    public ColorStateList getTint() {
+        return mNinePatchState.mTint;
     }
 
     /**
      * Specifies the blending mode used to apply tint.
      *
      * @param tintMode A Porter-Duff blending mode
+     * @hide Pending finalization of supported Modes
      */
     public void setTintMode(Mode tintMode) {
-        mNinePatchState.mTintMode = tintMode;
-        if (mTintFilter != null) {
-            mTintFilter.setMode(tintMode);
+        if (mNinePatchState.mTintMode != tintMode) {
+            mNinePatchState.mTintMode = tintMode;
+            updateTintFilter();
+            invalidateSelf();
         }
-        invalidateSelf();
+    }
+
+    /**
+     * Ensures the tint filter is consistent with the current tint color and
+     * mode.
+     */
+    private void updateTintFilter() {
+        final ColorStateList tint = mNinePatchState.mTint;
+        final Mode tintMode = mNinePatchState.mTintMode;
+        if (tint != null && tintMode != null) {
+            if (mTintFilter == null) {
+                mTintFilter = new PorterDuffColorFilter(0, tintMode);
+            } else {
+                mTintFilter.setMode(tintMode);
+            }
+        } else {
+            mTintFilter = null;
+        }
     }
 
     @Override
@@ -543,7 +564,7 @@
     final static class NinePatchState extends ConstantState {
         NinePatch mNinePatch;
         ColorStateList mTint;
-        Mode mTintMode;
+        Mode mTintMode = Mode.SRC_IN;
         Rect mPadding;
         Insets mOpticalInsets;
         boolean mDither;
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 93f2dc60..16de9f3 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -16,10 +16,18 @@
 
 package android.graphics.drawable;
 
-import android.graphics.*;
-import android.graphics.drawable.shapes.Shape;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.shapes.Shape;
 import android.util.AttributeSet;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -28,22 +36,24 @@
 import java.io.IOException;
 
 /**
- * A Drawable object that draws primitive shapes. 
- * A ShapeDrawable takes a {@link android.graphics.drawable.shapes.Shape}
- * object and manages its presence on the screen. If no Shape is given, then
- * the ShapeDrawable will default to a 
- * {@link android.graphics.drawable.shapes.RectShape}.
- *
- * <p>This object can be defined in an XML file with the <code>&lt;shape></code> element.</p>
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about how to use ShapeDrawable, read the
- * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#shape-drawable">
- * Canvas and Drawables</a> document. For more information about defining a ShapeDrawable in
- * XML, read the
- * <a href="{@docRoot}guide/topics/resources/drawable-resource.html#Shape">Drawable Resources</a>
- * document.</p></div>
+ * A Drawable object that draws primitive shapes. A ShapeDrawable takes a
+ * {@link android.graphics.drawable.shapes.Shape} object and manages its
+ * presence on the screen. If no Shape is given, then the ShapeDrawable will
+ * default to a {@link android.graphics.drawable.shapes.RectShape}.
+ * <p>
+ * This object can be defined in an XML file with the <code>&lt;shape></code>
+ * element.
+ * </p>
+ * <div class="special reference"> <h3>Developer Guides</h3>
+ * <p>
+ * For more information about how to use ShapeDrawable, read the <a
+ * href="{@docRoot}guide/topics/graphics/2d-graphics.html#shape-drawable">
+ * Canvas and Drawables</a> document. For more information about defining a
+ * ShapeDrawable in XML, read the <a href="{@docRoot}
+ * guide/topics/resources/drawable-resource.html#Shape">Drawable Resources</a>
+ * document.
+ * </p>
+ * </div>
  *
  * @attr ref android.R.styleable#ShapeDrawablePadding_left
  * @attr ref android.R.styleable#ShapeDrawablePadding_top
@@ -55,6 +65,7 @@
  */
 public class ShapeDrawable extends Drawable {
     private ShapeState mShapeState;
+    private PorterDuffColorFilter mTintFilter;
     private boolean mMutated;
 
     /**
@@ -63,20 +74,25 @@
     public ShapeDrawable() {
         this((ShapeState) null);
     }
-    
+
     /**
      * Creates a ShapeDrawable with a specified Shape.
-     * 
+     *
      * @param s the Shape that this ShapeDrawable should be
      */
     public ShapeDrawable(Shape s) {
         this((ShapeState) null);
-        
+
         mShapeState.mShape = s;
     }
-    
+
     private ShapeDrawable(ShapeState state) {
         mShapeState = new ShapeState(state);
+
+        if (state != null && state.mTint != null) {
+            final int color = state.mTint.getColorForState(getState(), 0);
+            mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
+        }
     }
 
     /**
@@ -85,7 +101,7 @@
     public Shape getShape() {
         return mShapeState.mShape;
     }
-    
+
     /**
      * Sets the Shape of this ShapeDrawable.
      */
@@ -93,19 +109,19 @@
         mShapeState.mShape = s;
         updateShape();
     }
-    
+
     /**
-     * Sets a ShaderFactory to which requests for a 
+     * Sets a ShaderFactory to which requests for a
      * {@link android.graphics.Shader} object will be made.
-     * 
+     *
      * @param fact an instance of your ShaderFactory implementation
      */
     public void setShaderFactory(ShaderFactory fact) {
         mShapeState.mShaderFactory = fact;
     }
-    
+
     /**
-     * Returns the ShaderFactory used by this ShapeDrawable for requesting a 
+     * Returns the ShaderFactory used by this ShapeDrawable for requesting a
      * {@link android.graphics.Shader}.
      */
     public ShaderFactory getShaderFactory() {
@@ -118,14 +134,14 @@
     public Paint getPaint() {
         return mShapeState.mPaint;
     }
-    
+
     /**
      * 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)
+     *
+     * @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) {
@@ -138,10 +154,10 @@
         }
         invalidateSelf();
     }
-    
+
     /**
-     * Sets padding for this shape, defined by a Rect object.
-     * Define the padding in the Rect object as: left, top, right, bottom.
+     * 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) {
         if (padding == null) {
@@ -154,37 +170,37 @@
         }
         invalidateSelf();
     }
-    
+
     /**
      * Sets the intrinsic (default) width for this shape.
-     * 
+     *
      * @param width the intrinsic width (in pixels)
      */
     public void setIntrinsicWidth(int width) {
         mShapeState.mIntrinsicWidth = width;
         invalidateSelf();
     }
-    
+
     /**
      * Sets the intrinsic (default) height for this shape.
-     * 
+     *
      * @param height the intrinsic height (in pixels)
      */
     public void setIntrinsicHeight(int height) {
         mShapeState.mIntrinsicHeight = height;
         invalidateSelf();
     }
-    
+
     @Override
     public int getIntrinsicWidth() {
         return mShapeState.mIntrinsicWidth;
     }
-    
+
     @Override
     public int getIntrinsicHeight() {
         return mShapeState.mIntrinsicHeight;
     }
-    
+
     @Override
     public boolean getPadding(Rect padding) {
         if (mShapeState.mPadding != null) {
@@ -196,14 +212,14 @@
     }
 
     private static int modulateAlpha(int paintAlpha, int alpha) {
-        int scale = alpha + (alpha >>> 7);  // convert to 0..256
+        int scale = alpha + (alpha >>> 7); // convert to 0..256
         return paintAlpha * scale >>> 8;
     }
 
     /**
-     * Called from the drawable's draw() method after the canvas has been set
-     * to draw the shape at (0,0). Subclasses can override for special effects
-     * such as multiple layers, stroking, etc.
+     * Called from the drawable's draw() method after the canvas has been set to
+     * draw the shape at (0,0). Subclasses can override for special effects such
+     * as multiple layers, stroking, etc.
      */
     protected void onDraw(Shape shape, Canvas canvas, Paint paint) {
         shape.draw(canvas, paint);
@@ -211,23 +227,37 @@
 
     @Override
     public void draw(Canvas canvas) {
-        Rect r = getBounds();
-        Paint paint = mShapeState.mPaint;
+        final Rect r = getBounds();
+        final ShapeState state = mShapeState;
+        final Paint paint = state.mPaint;
 
-        int prevAlpha = paint.getAlpha();
-        paint.setAlpha(modulateAlpha(prevAlpha, mShapeState.mAlpha));
+        final int prevAlpha = paint.getAlpha();
+        paint.setAlpha(modulateAlpha(prevAlpha, state.mAlpha));
 
         // only draw shape if it may affect output
         if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadow) {
-            if (mShapeState.mShape != null) {
-                // need the save both for the translate, and for the (unknown) Shape
-                int count = canvas.save();
+            final boolean clearColorFilter;
+            if (mTintFilter != null && paint.getColorFilter() == null) {
+                paint.setColorFilter(mTintFilter);
+                clearColorFilter = true;
+            } else {
+                clearColorFilter = false;
+            }
+
+            if (state.mShape != null) {
+                // need the save both for the translate, and for the (unknown)
+                // Shape
+                final int count = canvas.save();
                 canvas.translate(r.left, r.top);
-                onDraw(mShapeState.mShape, canvas, paint);
+                onDraw(state.mShape, canvas, paint);
                 canvas.restoreToCount(count);
             } else {
                 canvas.drawRect(r, paint);
             }
+
+            if (clearColorFilter) {
+                paint.setColorFilter(null);
+            }
         }
 
         // restore
@@ -239,16 +269,17 @@
         return super.getChangingConfigurations()
                 | mShapeState.mChangingConfigurations;
     }
-    
+
     /**
      * Set the alpha level for this drawable [0..255]. Note that this drawable
      * also has a color in its paint, which has an alpha as well. These two
      * values are automatically combined during drawing. Thus if the color's
      * alpha is 75% (i.e. 192) and the drawable's alpha is 50% (i.e. 128), then
-     * the combined alpha that will be used during drawing will be 37.5%
-     * (i.e. 96).
+     * the combined alpha that will be used during drawing will be 37.5% (i.e.
+     * 96).
      */
-    @Override public void setAlpha(int alpha) {
+    @Override
+    public void setAlpha(int alpha) {
         mShapeState.mAlpha = alpha;
         invalidateSelf();
     }
@@ -258,12 +289,81 @@
         return mShapeState.mAlpha;
     }
 
+    /**
+     * Specifies a tint for this drawable.
+     * <p>
+     * Setting a color filter via {@link #setColorFilter(ColorFilter)} overrides
+     * tint.
+     *
+     * @param tint Color state list to use for tinting this drawable, or null to
+     *            clear the tint
+     */
+    public void setTint(ColorStateList tint) {
+        if (mShapeState.mTint != tint) {
+            mShapeState.mTint = tint;
+            updateTintFilter();
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * Returns the tint color for this drawable.
+     *
+     * @return Color state list to use for tinting this drawable, or null if
+     *         none set
+     */
+    public ColorStateList getTint() {
+        return mShapeState.mTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply tint.
+     *
+     * @param tintMode A Porter-Duff blending mode
+     * @hide Pending finalization of supported Modes
+     */
+    public void setTintMode(Mode tintMode) {
+        if (mShapeState.mTintMode != tintMode) {
+            mShapeState.mTintMode = tintMode;
+            updateTintFilter();
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * Ensures the tint filter is consistent with the current tint color and
+     * mode.
+     */
+    private void updateTintFilter() {
+        final ColorStateList tint = mShapeState.mTint;
+        final Mode tintMode = mShapeState.mTintMode;
+        if (tint != null && tintMode != null) {
+            if (mTintFilter == null) {
+                mTintFilter = new PorterDuffColorFilter(0, tintMode);
+            } else {
+                mTintFilter.setMode(tintMode);
+            }
+        } else {
+            mTintFilter = null;
+        }
+    }
+
+    /**
+     * Returns the blending mode used to apply tint.
+     *
+     * @return The Porter-Duff blending mode used to apply tint.
+     * @hide Pending finalization of supported Modes
+     */
+    public Mode getTintMode() {
+        return mShapeState.mTintMode;
+    }
+
     @Override
     public void setColorFilter(ColorFilter cf) {
         mShapeState.mPaint.setColorFilter(cf);
         invalidateSelf();
     }
-    
+
     @Override
     public int getOpacity() {
         if (mShapeState.mShape == null) {
@@ -294,9 +394,31 @@
         updateShape();
     }
 
+    @Override
+    protected boolean onStateChange(int[] stateSet) {
+        final ColorStateList tint = mShapeState.mTint;
+        if (tint != null) {
+            final int newColor = tint.getColorForState(stateSet, 0);
+            final int oldColor = mTintFilter.getColor();
+            if (oldColor != newColor) {
+                mTintFilter.setColor(newColor);
+                invalidateSelf();
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean isStateful() {
+        final ShapeState s = mShapeState;
+        return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
+    }
+
     /**
-     * Subclasses override this to parse custom subelements.
-     * If you handle it, return true, else return <em>super.inflateTag(...)</em>.
+     * Subclasses override this to parse custom subelements. If you handle it,
+     * return true, else return <em>super.inflateTag(...)</em>.
      */
     protected boolean inflateTag(String name, Resources r, XmlPullParser parser,
             AttributeSet attrs) {
@@ -322,7 +444,7 @@
 
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
-                        throws XmlPullParserException, IOException {
+            throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs);
 
         TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ShapeDrawable);
@@ -343,12 +465,12 @@
 
         int type;
         final int outerDepth = parser.getDepth();
-        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-               && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            
+
             final String name = parser.getName();
             // call our subclass
             if (!inflateTag(name, r, parser, attrs)) {
@@ -371,7 +493,7 @@
         }
         invalidateSelf();
     }
-    
+
     @Override
     public ConstantState getConstantState() {
         mShapeState.mChangingConfigurations = getChangingConfigurations();
@@ -408,16 +530,20 @@
         int mChangingConfigurations;
         Paint mPaint;
         Shape mShape;
+        ColorStateList mTint;
+        Mode mTintMode = Mode.SRC_IN;
         Rect mPadding;
         int mIntrinsicWidth;
         int mIntrinsicHeight;
         int mAlpha = 255;
         ShaderFactory mShaderFactory;
-        
+
         ShapeState(ShapeState orig) {
             if (orig != null) {
                 mPaint = orig.mPaint;
                 mShape = orig.mShape;
+                mTint = orig.mTint;
+                mTintMode = orig.mTintMode;
                 mPadding = orig.mPadding;
                 mIntrinsicWidth = orig.mIntrinsicWidth;
                 mIntrinsicHeight = orig.mIntrinsicHeight;
@@ -427,48 +553,45 @@
                 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
             }
         }
-        
+
         @Override
         public Drawable newDrawable() {
             return new ShapeDrawable(this);
         }
-        
+
         @Override
         public Drawable newDrawable(Resources res) {
             return new ShapeDrawable(this);
         }
-        
+
         @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
         }
     }
-    
+
     /**
      * Base class defines a factory object that is called each time the drawable
      * is resized (has a new width or height). Its resize() method returns a
-     * corresponding shader, or null.
-     * Implement this class if you'd like your ShapeDrawable to use a special
-     * {@link android.graphics.Shader}, such as a 
-     * {@link android.graphics.LinearGradient}. 
-     * 
+     * corresponding shader, or null. Implement this class if you'd like your
+     * ShapeDrawable to use a special {@link android.graphics.Shader}, such as a
+     * {@link android.graphics.LinearGradient}.
      */
     public static abstract class ShaderFactory {
         /**
-         * Returns the Shader to be drawn when a Drawable is drawn.
-         * The dimensions of the Drawable are passed because they may be needed
-         * to adjust how the Shader is configured for drawing.
-         * This is called by ShapeDrawable.setShape().
-         * 
-         * @param width  the width of the Drawable being drawn
+         * Returns the Shader to be drawn when a Drawable is drawn. The
+         * dimensions of the Drawable are passed because they may be needed to
+         * adjust how the Shader is configured for drawing. This is called by
+         * ShapeDrawable.setShape().
+         *
+         * @param width the width of the Drawable being drawn
          * @param height the heigh of the Drawable being drawn
-         * @return       the Shader to be drawn
+         * @return the Shader to be drawn
          */
         public abstract Shader resize(int width, int height);
     }
-    
+
     // other subclass could wack the Shader's localmatrix based on the
     // resize params (e.g. scaletofit, etc.). This could be used to scale
     // a bitmap to fill the bounds without needing any other special casing.
 }
-
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index b8d3f48..302fbf6 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -1083,7 +1083,7 @@
     }
 
     if (readSnapshot.size() != 4) {
-        fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
+        fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size());
         return 1;
     }
 
@@ -1095,8 +1095,8 @@
         if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
                 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
                 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
-            fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
-                            "          actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
+            fprintf(stderr, "state %zu expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
+                            "          actual={%d/%d, 0x%08x, %04o, 0x%08x, %3zu} '%s'\n", i,
                     states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
                     states[i].crc32, name.length(), filenames[i].string(),
                     state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
@@ -1230,7 +1230,7 @@
         goto finished;
     }
     if ((int)actualSize != bufSize) {
-        fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
+        fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08zx\n", bufSize,
                 actualSize);
         err = EINVAL;
         goto finished;
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 1f5d26c..4935b34 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -21,6 +21,7 @@
 #include <utils/Vector.h>
 
 #include "AmbientShadow.h"
+#include "ShadowTessellator.h"
 #include "Vertex.h"
 
 namespace android {
@@ -34,9 +35,7 @@
  *                  array.
  * @param vertexCount The length of caster's polygon in terms of number of
  *                    vertices.
- * @param rays The number of rays shooting out from the centroid.
- * @param layers The number of rings outside the polygon.
- * @param strength The darkness of the shadow, the higher, the darker.
+ * @param centroid3d The centroid of the shadow caster.
  * @param heightFactor The factor showing the higher the object, the lighter the
  *                     shadow.
  * @param geomFactor The factor scaling the geometry expansion along the normal.
@@ -45,21 +44,18 @@
  *               triangle strips mode.
  */
 void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount,
-        int rays, int layers, float strength, float heightFactor, float geomFactor,
+        const Vector3& centroid3d, float heightFactor, float geomFactor,
         VertexBuffer& shadowVertexBuffer) {
-
+    const int rays = SHADOW_RAY_COUNT;
+    const int layers = SHADOW_LAYER_COUNT;
     // Validate the inputs.
-    if (strength <= 0 || heightFactor <= 0 || layers <= 0 || rays <= 0
+    if (vertexCount < 3 || heightFactor <= 0 || layers <= 0 || rays <= 0
         || geomFactor <= 0) {
 #if DEBUG_SHADOW
         ALOGE("Invalid input for createAmbientShadow(), early return!");
 #endif
         return;
     }
-    int rings = layers + 1;
-    int size = rays * rings;
-    Vector2 centroid;
-    calculatePolygonCentroid(vertices, vertexCount, centroid);
 
     Vector<Vector2> dir; // TODO: use C++11 unique_ptr
     dir.setCapacity(rays);
@@ -75,7 +71,7 @@
         int edgeIndex;
         float edgeFraction;
         float rayDistance;
-        calculateIntersection(vertices, vertexCount, centroid, dir[i], edgeIndex,
+        calculateIntersection(vertices, vertexCount, centroid3d, dir[i], edgeIndex,
                 edgeFraction, rayDistance);
         rayDist[i] = rayDistance;
         if (edgeIndex < 0 || edgeIndex >= vertexCount) {
@@ -91,8 +87,7 @@
 
     // The output buffer length basically is roughly rays * layers, but since we
     // need triangle strips, so we need to duplicate vertices to accomplish that.
-    const int shadowVertexCount = (2 + rays + ((layers) * 2 * (rays + 1)));
-    AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(shadowVertexCount);
+    AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(SHADOW_VERTEX_COUNT);
 
     // Calculate the vertex of the shadows.
     //
@@ -101,110 +96,45 @@
     // calculate the normal N, which should be perpendicular to the edge of the
     // polygon (represented by the neighbor intersection points) .
     // Shadow's vertices will be generated as : P + N * scale.
-    int currentIndex = 0;
-    for (int r = 0; r < layers; r++) {
-        int firstInLayer = currentIndex;
-        for (int i = 0; i < rays; i++) {
+    int currentVertexIndex = 0;
+    for (int layerIndex = 0; layerIndex <= layers; layerIndex++) {
+        for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
 
             Vector2 normal(1.0f, 0.0f);
-            calculateNormal(rays, i, dir.array(), rayDist, normal);
+            calculateNormal(rays, rayIndex, dir.array(), rayDist, normal);
 
-            float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor);
+            float opacity = 1.0 / (1 + rayHeight[rayIndex] / heightFactor);
 
             // The vertex should be start from rayDist[i] then scale the
             // normalizeNormal!
-            Vector2 intersection = dir[i] * rayDist[i] + centroid;
+            Vector2 intersection = dir[rayIndex] * rayDist[rayIndex] +
+                    Vector2(centroid3d.x, centroid3d.y);
 
-            // Use 2 rings' vertices to complete one layer's strip
-            for (int j = r; j < (r + 2); j++) {
-                float jf = j / (float)(rings - 1);
-
-                float expansionDist = rayHeight[i] / heightFactor * geomFactor * jf;
-                AlphaVertex::set(&shadowVertices[currentIndex],
-                        intersection.x + normal.x * expansionDist,
-                        intersection.y + normal.y * expansionDist,
-                        (1 - jf) * opacity);
-                currentIndex++;
-            }
+            float layerRatio = layerIndex / (float)(layers);
+            // The higher the intersection is, the further the ambient shadow expanded.
+            float expansionDist = rayHeight[rayIndex] / heightFactor *
+                    geomFactor * (1 - layerRatio);
+            AlphaVertex::set(&shadowVertices[currentVertexIndex++],
+                    intersection.x + normal.x * expansionDist,
+                    intersection.y + normal.y * expansionDist,
+                    layerRatio * opacity);
         }
 
-        // From one layer to the next, we need to duplicate the vertex to
-        // continue as a single strip.
-        shadowVertices[currentIndex] = shadowVertices[firstInLayer];
-        currentIndex++;
-        shadowVertices[currentIndex] = shadowVertices[firstInLayer + 1];
-        currentIndex++;
     }
+    float centroidAlpha = 1.0 / (1 + centroid3d.z / heightFactor);
+    AlphaVertex::set(&shadowVertices[currentVertexIndex++],
+            centroid3d.x, centroid3d.y, centroidAlpha);
 
-    // After all rings are done, we need to jump into the polygon.
-    // In order to keep everything in a strip, we need to duplicate the last one
-    // of the rings and the first one inside the polygon.
-    int lastInRings = currentIndex - 1;
-    shadowVertices[currentIndex] = shadowVertices[lastInRings];
-    currentIndex++;
-
-    // We skip one and fill it back after we finish the internal triangles.
-    currentIndex++;
-    int firstInternal = currentIndex;
-
-    // Combine the internal area of the polygon into a triangle strip, too.
-    // The basic idea is zig zag between the intersection points.
-    // 0 -> (n - 1) -> 1 -> (n - 2) ...
-    for (int k = 0; k < rays; k++) {
-        int  i = k / 2;
-        if ((k & 1) == 1) { // traverse the inside in a zig zag pattern for strips
-            i = rays - i - 1;
-        }
-        float cast = rayDist[i] * (1 + rayHeight[i] / heightFactor);
-        float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor);
-        float t = rayDist[i];
-
-        AlphaVertex::set(&shadowVertices[currentIndex], dir[i].x * t + centroid.x,
-                dir[i].y * t + centroid.y, opacity);
-        currentIndex++;
-    }
-
-    currentIndex = firstInternal - 1;
-    shadowVertices[currentIndex] = shadowVertices[firstInternal];
-}
-
-/**
- * Calculate the centroid of a given polygon.
- *
- * @param vertices The shadow caster's polygon, which is represented in a
- *                 straight Vector3 array.
- * @param vertexCount The length of caster's polygon in terms of number of vertices.
- *
- * @param centroid Return the centroid of the polygon.
- */
-void AmbientShadow::calculatePolygonCentroid(const Vector3* vertices, int vertexCount,
-        Vector2& centroid) {
-    float sumx = 0;
-    float sumy = 0;
-    int p1 = vertexCount - 1;
-    float area = 0;
-    for (int p2 = 0; p2 < vertexCount; p2++) {
-        float x1 = vertices[p1].x;
-        float y1 = vertices[p1].y;
-        float x2 = vertices[p2].x;
-        float y2 = vertices[p2].y;
-        float a = (x1 * y2 - x2 * y1);
-        sumx += (x1 + x2) * a;
-        sumy += (y1 + y2) * a;
-        area += a;
-        p1 = p2;
-    }
-
-    if (area == 0) {
 #if DEBUG_SHADOW
-        ALOGE("Area is 0!");
-#endif
-        centroid.x = vertices[0].x;
-        centroid.y = vertices[0].y;
-    } else {
-        centroid.x = sumx / (3 * area);
-        centroid.y = sumy / (3 * area);
+    if (currentVertexIndex != SHADOW_VERTEX_COUNT) {
+        ALOGE("number of vertex generated for ambient shadow is wrong! "
+              "current: %d , expected: %d", currentVertexIndex, SHADOW_VERTEX_COUNT);
     }
+    for (int i = 0; i < SHADOW_VERTEX_COUNT; i++) {
+        ALOGD("ambient shadow value: i %d, (x:%f, y:%f, a:%f)", i, shadowVertices[i].x,
+                shadowVertices[i].y, shadowVertices[i].alpha);
+    }
+#endif
 }
 
 /**
@@ -238,7 +168,7 @@
  * @param outRayDist Return the ray distance from centroid to the intersection.
  */
 void AmbientShadow::calculateIntersection(const Vector3* vertices, int vertexCount,
-        const Vector2& start, const Vector2& dir, int& outEdgeIndex,
+        const Vector3& start, const Vector2& dir, int& outEdgeIndex,
         float& outEdgeFraction, float& outRayDist) {
     float startX = start.x;
     float startY = start.y;
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 079bdb7..20d1384 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -34,17 +34,15 @@
  */
 class AmbientShadow {
 public:
-    static void createAmbientShadow(const Vector3* poly, int polyLength, int rays,
-            int layers, float strength, float heightFactor, float geomFactor,
+    static void createAmbientShadow(const Vector3* poly, int polyLength,
+            const Vector3& centroid3d, float heightFactor, float geomFactor,
             VertexBuffer& shadowVertexBuffer);
 
 private:
-    static void calculatePolygonCentroid(const Vector3* poly, int len, Vector2& centroid);
-
     static void calculateRayDirections(int rays, Vector2* dir);
 
     static void calculateIntersection(const Vector3* poly, int nbVertices,
-            const Vector2& start, const Vector2& dir, int& outEdgeIndex,
+            const Vector3& start, const Vector2& dir, int& outEdgeIndex,
             float& outEdgeFraction, float& outRayDist);
 
     static void calculateNormal(int rays, int currentRayIndex, const Vector2* dir,
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 495ad19..2cc7a84 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -61,12 +61,7 @@
 	LOCAL_C_INCLUDES += \
 		$(JNI_H_INCLUDE) \
 		$(LOCAL_PATH)/../../include/utils \
-		external/skia/include/core \
-		external/skia/include/effects \
-		external/skia/include/images \
-		external/skia/src/core \
-		external/skia/src/ports \
-		external/skia/include/utils
+		external/skia/src/core
 
 	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
 	LOCAL_CFLAGS += -Wno-unused-parameter
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 21cf658..1d58d96 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -23,6 +23,7 @@
 #include "DisplayListRenderer.h"
 #include "Properties.h"
 #include "LayerRenderer.h"
+#include "ShadowTessellator.h"
 
 namespace android {
 
@@ -86,7 +87,7 @@
 
     mRegionMesh = NULL;
     mMeshIndices = 0;
-
+    mShadowStripsIndices = 0;
     blend = false;
     lastSrcMode = GL_ZERO;
     lastDstMode = GL_ZERO;
@@ -223,6 +224,9 @@
     mMeshIndices = 0;
     mRegionMesh = NULL;
 
+    glDeleteBuffers(1, &mShadowStripsIndices);
+    mShadowStripsIndices = 0;
+
     fboCache.clear();
 
     programCache.clear();
@@ -404,7 +408,7 @@
     return false;
 }
 
-bool Caches::bindIndicesBuffer(const GLuint buffer) {
+bool Caches::bindIndicesBufferInternal(const GLuint buffer) {
     if (mCurrentIndicesBuffer != buffer) {
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
         mCurrentIndicesBuffer = buffer;
@@ -413,7 +417,7 @@
     return false;
 }
 
-bool Caches::bindIndicesBuffer() {
+bool Caches::bindQuadIndicesBuffer() {
     if (!mMeshIndices) {
         uint16_t* regionIndices = new uint16_t[gMaxNumberOfQuads * 6];
         for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
@@ -428,7 +432,7 @@
         }
 
         glGenBuffers(1, &mMeshIndices);
-        bool force = bindIndicesBuffer(mMeshIndices);
+        bool force = bindIndicesBufferInternal(mMeshIndices);
         glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
                 regionIndices, GL_STATIC_DRAW);
 
@@ -436,7 +440,23 @@
         return force;
     }
 
-    return bindIndicesBuffer(mMeshIndices);
+    return bindIndicesBufferInternal(mMeshIndices);
+}
+
+bool Caches::bindShadowIndicesBuffer() {
+    if (!mShadowStripsIndices) {
+        uint16_t* shadowIndices = new uint16_t[SHADOW_INDEX_COUNT];
+        ShadowTessellator::generateShadowIndices(shadowIndices);
+        glGenBuffers(1, &mShadowStripsIndices);
+        bool force = bindIndicesBufferInternal(mShadowStripsIndices);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, SHADOW_INDEX_COUNT * sizeof(uint16_t),
+            shadowIndices, GL_STATIC_DRAW);
+
+        delete[] shadowIndices;
+        return force;
+    }
+
+    return bindIndicesBufferInternal(mShadowStripsIndices);
 }
 
 bool Caches::unbindIndicesBuffer() {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 2cc15cc..8c0c508 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -190,8 +190,8 @@
      * Binds a global indices buffer that can draw up to
      * gMaxNumberOfQuads quads.
      */
-    bool bindIndicesBuffer();
-    bool bindIndicesBuffer(const GLuint buffer);
+    bool bindQuadIndicesBuffer();
+    bool bindShadowIndicesBuffer();
     bool unbindIndicesBuffer();
 
     /**
@@ -381,6 +381,8 @@
     void initConstraints();
     void initStaticProperties();
 
+    bool bindIndicesBufferInternal(const GLuint buffer);
+
     static void eventMarkNull(GLsizei length, const GLchar* marker) { }
     static void startMarkNull(GLsizei length, const GLchar* marker) { }
     static void endMarkNull() { }
@@ -417,6 +419,7 @@
 
     // Global index buffer
     GLuint mMeshIndices;
+    GLuint mShadowStripsIndices;
 
     mutable Mutex mGarbageLock;
     Vector<Layer*> mLayerGarbage;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 62f6c76..7a2e288 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -112,6 +112,15 @@
             frameNumber = newFrameNumber;
             dropCounter++;
         }
+
+        bool forceFilter = false;
+        sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer();
+        if (buffer != NULL) {
+            // force filtration if buffer size != layer size
+            forceFilter = mWidth != buffer->getWidth()
+                    || mHeight != buffer->getHeight();
+        }
+
         #if DEBUG_RENDERER
         if (dropCounter > 0) {
             RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
@@ -120,8 +129,8 @@
         mSurfaceTexture->getTransformMatrix(transform);
         GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
 
-        LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight, !mBlend,
-                renderTarget, transform);
+        LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight,
+                !mBlend, forceFilter, renderTarget, transform);
     }
 }
 
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index b5a66f6..65eda29 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -788,7 +788,7 @@
         deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
                 !state.mClipSideFlags &&
                 OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
-                (mBitmap->getConfig() != SkBitmap::kA8_Config);
+                (mBitmap->config() != SkBitmap::kA8_Config);
     }
 
     const SkBitmap* bitmap() { return mBitmap; }
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index b79a3b0..b52003c 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -498,7 +498,7 @@
                 }
 
                 checkTextureUpdate();
-                caches.bindIndicesBuffer();
+                caches.bindQuadIndicesBuffer();
 
                 if (!mDrawn) {
                     // If returns true, a VBO was bound and we must
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 54ce64f..8992a13 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -46,6 +46,7 @@
     stencil = NULL;
     debugDrawUpdate = false;
     hasDrawnSinceUpdate = false;
+    forceFilter = false;
     deferredList = NULL;
     caches.resourceCache.incrementRefcount(this);
 }
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 8cc027a..f6538f2 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -127,6 +127,14 @@
         return texture.blend;
     }
 
+    inline void setForceFilter(bool forceFilter) {
+        this->forceFilter = forceFilter;
+    }
+
+    inline bool getForceFilter() const {
+        return forceFilter;
+    }
+
     inline void setAlpha(int alpha) {
         this->alpha = alpha;
     }
@@ -343,9 +351,15 @@
     SkColorFilter* colorFilter;
 
     /**
+     * Indicates raster data backing the layer is scaled, requiring filtration.
+     */
+    bool forceFilter;
+
+    /**
      * Opacity of the layer.
      */
     int alpha;
+
     /**
      * Blending mode of the layer.
      */
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index ea8eb31..e0ac2ba 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -290,14 +290,15 @@
 }
 
 void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
-        bool isOpaque, GLenum renderTarget, float* transform) {
+        bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform) {
     if (layer) {
         layer->setBlend(!isOpaque);
+        layer->setForceFilter(forceFilter);
         layer->setSize(width, height);
         layer->layer.set(0.0f, 0.0f, width, height);
         layer->region.set(width, height);
         layer->regionRect.set(0.0f, 0.0f, width, height);
-        layer->getTexTransform().load(transform);
+        layer->getTexTransform().load(textureTransform);
 
         if (renderTarget != layer->getRenderTarget()) {
             layer->setRenderTarget(renderTarget);
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 84acd44..40e461a 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -56,7 +56,7 @@
     ANDROID_API static Layer* createRenderLayer(uint32_t width, uint32_t height);
     ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
     ANDROID_API static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
-            bool isOpaque, GLenum renderTarget, float* transform);
+            bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform);
     ANDROID_API static void destroyLayer(Layer* layer);
     ANDROID_API static void destroyLayerDeferred(Layer* layer);
     ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 75bf716..b620b80 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -52,7 +52,12 @@
 
 #define ALPHA_THRESHOLD 0
 
-#define FILTER(paint) (!paint || paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST)
+static GLenum getFilter(const SkPaint* paint) {
+    if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
+        return GL_LINEAR;
+    }
+    return GL_NEAREST;
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 // Globals
@@ -1068,6 +1073,7 @@
         setupDrawExternalTexture(layer->getTexture());
     }
     if (currentTransform()->isPureTranslate() &&
+            !layer->getForceFilter() &&
             layer->getWidth() == (uint32_t) rect.getWidth() &&
             layer->getHeight() == (uint32_t) rect.getHeight()) {
         const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
@@ -1902,7 +1908,7 @@
     } else {
         force = mCaches.unbindMeshBuffer();
     }
-    mCaches.bindIndicesBuffer();
+    mCaches.bindQuadIndicesBuffer();
 
     mCaches.bindPositionVertexPointer(force, vertices);
     if (mCaches.currentProgram->texCoords >= 0) {
@@ -1912,7 +1918,7 @@
 
 void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
     bool force = mCaches.unbindMeshBuffer();
-    mCaches.bindIndicesBuffer();
+    mCaches.bindQuadIndicesBuffer();
     mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
 }
 
@@ -1972,7 +1978,7 @@
 
         texture->setFilter(GL_NEAREST, true);
     } else {
-        texture->setFilter(FILTER(paint), true);
+        texture->setFilter(getFilter(paint), true);
     }
 
     // No need to check for a UV mapper on the texture object, only ARGB_8888
@@ -1997,7 +2003,7 @@
     const AutoTexture autoCleanup(texture);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(pureTranslate ? GL_NEAREST : FILTER(paint), true);
+    texture->setFilter(pureTranslate ? GL_NEAREST : getFilter(paint), true);
 
     const float x = (int) floorf(bounds.left + 0.5f);
     const float y = (int) floorf(bounds.top + 0.5f);
@@ -2173,7 +2179,7 @@
     const AutoTexture autoCleanup(texture);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(FILTER(paint), true);
+    texture->setFilter(getFilter(paint), true);
 
     int alpha;
     SkXfermode::Mode mode;
@@ -2258,10 +2264,10 @@
         dstLeft = x;
         dstTop = y;
 
-        texture->setFilter(scaled ? FILTER(paint) : GL_NEAREST, true);
+        texture->setFilter(scaled ? getFilter(paint) : GL_NEAREST, true);
         ignoreTransform = true;
     } else {
-        texture->setFilter(FILTER(paint), true);
+        texture->setFilter(getFilter(paint), true);
     }
 
     if (CC_UNLIKELY(useScaleTransform)) {
@@ -2387,10 +2393,9 @@
     return DrawGlInfo::kStatusDrew;
 }
 
-status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, const SkPaint* paint,
-        bool useOffset) {
+status_t OpenGLRenderer::drawVertexBuffer(VertexBufferMode mode,
+        const VertexBuffer& vertexBuffer, const SkPaint* paint, bool useOffset) {
     // not missing call to quickReject/dirtyLayer, always done at a higher level
-
     if (!vertexBuffer.getVertexCount()) {
         // no vertices to draw
         return DrawGlInfo::kStatusDone;
@@ -2416,19 +2421,24 @@
     bool force = mCaches.unbindMeshBuffer();
     mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
     mCaches.resetTexCoordsVertexPointer();
-    mCaches.unbindIndicesBuffer();
+
 
     int alphaSlot = -1;
     if (isAA) {
         void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
         alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
-
         // TODO: avoid enable/disable in back to back uses of the alpha attribute
         glEnableVertexAttribArray(alphaSlot);
         glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
     }
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
+    if (mode == kVertexBufferMode_Standard) {
+        mCaches.unbindIndicesBuffer();
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
+    } else {
+        mCaches.bindShadowIndicesBuffer();
+        glDrawElements(GL_TRIANGLE_STRIP, SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
+    }
 
     if (isAA) {
         glDisableVertexAttribArray(alphaSlot);
@@ -2457,7 +2467,7 @@
         dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
     }
 
-    return drawVertexBuffer(vertexBuffer, paint);
+    return drawVertexBuffer(kVertexBufferMode_Standard, vertexBuffer, paint);
 }
 
 /**
@@ -2488,7 +2498,7 @@
     dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
 
     bool useOffset = !paint->isAntiAlias();
-    return drawVertexBuffer(buffer, paint, useOffset);
+    return drawVertexBuffer(kVertexBufferMode_Standard, buffer, paint, useOffset);
 }
 
 status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
@@ -2508,7 +2518,7 @@
     dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
 
     bool useOffset = !paint->isAntiAlias();
-    return drawVertexBuffer(buffer, paint, useOffset);
+    return drawVertexBuffer(kVertexBufferMode_Standard, buffer, paint, useOffset);
 }
 
 status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -3231,13 +3241,20 @@
         casterTransform.mapPoint3d(casterPolygon[i]);
     }
 
+    // map the centroid of the caster into 3d
+    Vector2 centroid =  ShadowTessellator::centroid2d(
+            reinterpret_cast<const Vector2*>(casterVertices2d.array()),
+            casterVertexCount);
+    Vector3 centroid3d(centroid.x, centroid.y, 0);
+    casterTransform.mapPoint3d(centroid3d);
+
     // draw caster's shadows
     if (mCaches.propertyAmbientShadowStrength > 0) {
         paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0);
         VertexBuffer ambientShadowVertexBuffer;
         ShadowTessellator::tessellateAmbientShadow(casterPolygon, casterVertexCount,
-                ambientShadowVertexBuffer);
-        drawVertexBuffer(ambientShadowVertexBuffer, &paint);
+                centroid3d, ambientShadowVertexBuffer);
+        drawVertexBuffer(kVertexBufferMode_Shadow, ambientShadowVertexBuffer, &paint);
     }
 
     if (mCaches.propertySpotShadowStrength > 0) {
@@ -3249,7 +3266,7 @@
                 lightPosScale, *currentTransform(), getWidth(), getHeight(),
                 spotShadowVertexBuffer);
 
-        drawVertexBuffer(spotShadowVertexBuffer, &paint);
+        drawVertexBuffer(kVertexBufferMode_Shadow, spotShadowVertexBuffer, &paint);
     }
 
     return DrawGlInfo::kStatusDrew;
@@ -3370,7 +3387,7 @@
                 paint, texture->blend, vertices, texCoords,
                 GL_TRIANGLE_STRIP, gMeshCount, false, true);
     } else {
-        texture->setFilter(FILTER(paint), true);
+        texture->setFilter(getFilter(paint), true);
         drawTextureMesh(left, top, right, bottom, texture->id, paint,
                 texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
     }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index e4d133d..03beae3 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -117,6 +117,11 @@
     kModelViewMode_TranslateAndScale = 1,
 };
 
+enum VertexBufferMode {
+    kVertexBufferMode_Standard = 0,
+    kVertexBufferMode_Shadow = 1
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 // Renderer
 ///////////////////////////////////////////////////////////////////////////////
@@ -629,8 +634,8 @@
      * @param paint The paint to render with
      * @param useOffset Offset the vertexBuffer (used in drawing non-AA lines)
      */
-    status_t drawVertexBuffer(const VertexBuffer& vertexBuffer, const SkPaint* paint,
-            bool useOffset = false);
+    status_t drawVertexBuffer(VertexBufferMode mode, const VertexBuffer& vertexBuffer,
+            const SkPaint* paint, bool useOffset = false);
 
     /**
      * Renders the convex hull defined by the specified path as a strip of polygons.
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index dc0d98c..8a44604 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -129,7 +129,11 @@
         Mutex::Autolock _l(mLock);
         size_t count = mGarbage.size();
         for (size_t i = 0; i < count; i++) {
-            remove(patchesToRemove, mGarbage[i]);
+            Res_png_9patch* patch = mGarbage[i];
+            remove(patchesToRemove, patch);
+            // A Res_png_9patch is actually an array of byte that's larger
+            // than sizeof(Res_png_9patch). It must be freed as an array.
+            delete[] (int8_t*) patch;
         }
         mGarbage.clear();
     }
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 9459885..5a49f38 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -395,7 +395,9 @@
         Mutex::Autolock l(mLock);
         size_t count = mGarbage.size();
         for (size_t i = 0; i < count; i++) {
-            remove(pathsToRemove, mGarbage.itemAt(i));
+            const path_pair_t& pair = mGarbage.itemAt(i);
+            remove(pathsToRemove, pair);
+            delete pair.getFirst();
         }
         mGarbage.clear();
     }
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 457cfa9..5562f34 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -193,8 +193,9 @@
         // If we're not tracking this resource, just delete it
         if (Caches::hasInstance()) {
             Caches::getInstance().pathCache.removeDeferred(resource);
+        } else {
+            delete resource;
         }
-        delete resource;
         return;
     }
     ref->destroyed = true;
@@ -215,8 +216,9 @@
         // If we're not tracking this resource, just delete it
         if (Caches::hasInstance()) {
             Caches::getInstance().textureCache.removeDeferred(resource);
+        } else {
+            delete resource;
         }
-        delete resource;
         return;
     }
     ref->destroyed = true;
@@ -253,13 +255,14 @@
     ssize_t index = mCache->indexOfKey(resource);
     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
     if (ref == NULL) {
+        // If we're not tracking this resource, just delete it
         if (Caches::hasInstance()) {
             Caches::getInstance().patchCache.removeDeferred(resource);
+        } else {
+            // A Res_png_9patch is actually an array of byte that's larger
+            // than sizeof(Res_png_9patch). It must be freed as an array.
+            delete[] (int8_t*) resource;
         }
-        // If we're not tracking this resource, just delete it
-        // A Res_png_9patch is actually an array of byte that's larger
-        // than sizeof(Res_png_9patch). It must be freed as an array.
-        delete[] (int8_t*) resource;
         return;
     }
     ref->destroyed = true;
@@ -316,16 +319,18 @@
                 SkBitmap* bitmap = (SkBitmap*) resource;
                 if (Caches::hasInstance()) {
                     Caches::getInstance().textureCache.removeDeferred(bitmap);
+                } else {
+                    delete bitmap;
                 }
-                delete bitmap;
             }
             break;
             case kPath: {
                 SkPath* path = (SkPath*) resource;
                 if (Caches::hasInstance()) {
                     Caches::getInstance().pathCache.removeDeferred(path);
+                } else {
+                    delete path;
                 }
-                delete path;
             }
             break;
             case kShader: {
@@ -336,11 +341,12 @@
             case kNinePatch: {
                 if (Caches::hasInstance()) {
                     Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
+                } else {
+                    // A Res_png_9patch is actually an array of byte that's larger
+                    // than sizeof(Res_png_9patch). It must be freed as an array.
+                    int8_t* patch = (int8_t*) resource;
+                    delete[] patch;
                 }
-                // A Res_png_9patch is actually an array of byte that's larger
-                // than sizeof(Res_png_9patch). It must be freed as an array.
-                int8_t* patch = (int8_t*) resource;
-                delete[] patch;
             }
             break;
             case kLayer: {
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 7700ea0..526772b 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -31,18 +31,16 @@
     return a > b ? a : b;
 }
 
-void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon, int casterVertexCount,
+void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon,
+        int casterVertexCount, const Vector3& centroid3d,
         VertexBuffer& shadowVertexBuffer) {
     // A bunch of parameters to tweak the shadow.
     // TODO: Allow some of these changable by debug settings or APIs.
-    const int rays = 128;
-    const int layers = 2;
-    const float strength = 0.5;
     const float heightFactor = 128;
     const float geomFactor = 64;
 
-    AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount, rays, layers, strength,
-            heightFactor, geomFactor, shadowVertexBuffer);
+    AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount,
+            centroid3d, heightFactor, geomFactor, shadowVertexBuffer);
 
 }
 
@@ -51,9 +49,6 @@
         int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
     // A bunch of parameters to tweak the shadow.
     // TODO: Allow some of these changable by debug settings or APIs.
-    const int rays = 256;
-    const int layers = 2;
-    const float strength = 0.5;
     int maximal = max(screenWidth, screenHeight);
     Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y,
             maximal * lightPosScale.z);
@@ -70,9 +65,77 @@
     const float lightSize = maximal / 4;
     const int lightVertexCount = 16;
 
-    SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter, lightSize,
-            lightVertexCount, rays, layers, strength, shadowVertexBuffer);
+    SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter,
+            lightSize, lightVertexCount, shadowVertexBuffer);
 
 }
+
+void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
+    int currentIndex = 0;
+    const int layers = SHADOW_LAYER_COUNT;
+    const int rays = SHADOW_RAY_COUNT;
+    // For the penumbra area.
+    for (int i = 0; i < layers; i++) {
+        for (int j = 0; j < rays; j++) {
+            shadowIndices[currentIndex++] = i * rays + j;
+            shadowIndices[currentIndex++] = (i + 1) * rays + j;
+        }
+        // To close the loop, back to the ray 0.
+        shadowIndices[currentIndex++] = i * rays;
+        shadowIndices[currentIndex++] = (i + 1) * rays;
+    }
+    uint16_t base = layers * rays;
+    uint16_t centroidIndex = (layers + 1) * rays;
+    // For the umbra area, using strips to simulate the fans.
+    for (int k = 0; k < rays; k++) {
+        shadowIndices[currentIndex++] = base + k;
+        shadowIndices[currentIndex++] = centroidIndex;
+    }
+    shadowIndices[currentIndex++] = base;
+
+#if DEBUG_SHADOW
+    if (currentIndex != SHADOW_INDEX_COUNT) {
+        ALOGE("vertex index count is wrong. current %d, expected %d",
+                currentIndex, SHADOW_INDEX_COUNT);
+    }
+    for (int i = 0; i < SHADOW_INDEX_COUNT; i++) {
+        ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
+    }
+#endif
+}
+
+/**
+ * Calculate the centroid of a 2d polygon.
+ *
+ * @param poly The polygon, which is represented in a Vector2 array.
+ * @param polyLength The length of the polygon in terms of number of vertices.
+ * @return the centroid of the polygon.
+ */
+Vector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) {
+    double sumx = 0;
+    double sumy = 0;
+    int p1 = polyLength - 1;
+    double area = 0;
+    for (int p2 = 0; p2 < polyLength; p2++) {
+        double x1 = poly[p1].x;
+        double y1 = poly[p1].y;
+        double x2 = poly[p2].x;
+        double y2 = poly[p2].y;
+        double a = (x1 * y2 - x2 * y1);
+        sumx += (x1 + x2) * a;
+        sumy += (y1 + y2) * a;
+        area += a;
+        p1 = p2;
+    }
+
+    Vector2 centroid = poly[0];
+    if (area != 0) {
+        centroid = Vector2(sumx / (3 * area), sumy / (3 * area));
+    } else {
+        ALOGE("Area is 0 while computing centroid!");
+    }
+    return centroid;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index ef95609..c49fdcb1 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -20,18 +20,57 @@
 
 #include "Debug.h"
 #include "Matrix.h"
+#include "VertexBuffer.h"
 
 namespace android {
 namespace uirenderer {
 
+// All SHADOW_* are used to define all the geometry property of shadows.
+// Use a simplified example to illustrate the geometry setup here.
+// Assuming we use 6 rays and only 1 layer, Then we will have 2 hexagons, which
+// are 0 to 5 and 6 to 11. The area between them will be the penumbra area, and
+// the area inside the 2nd hexagon is the umbra.
+// Also, we need to add the centroid "12" to draw the umbra area as triangle fans.
+//
+// Triange strip indices for penumbra area: (0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11, 0, 6)
+// Triange strip indices for numbra area: (6, 12, 7, 12, 8, 12, 9, 12, 10, 12, 11, 12, 6)
+//                 0
+//
+//      5          6         1
+//           11         7
+//                12
+//           10         8
+//      4          9         2
+//
+//                 3
+
+// The total number of rays starting from the centroid of shadow area, in order
+// to generate the shadow geometry.
+#define SHADOW_RAY_COUNT 256
+
+// The total number of layers in the outer shadow area, 1 being the minimum.
+#define SHADOW_LAYER_COUNT 2
+
+// The total number of all the vertices representing the shadow.
+#define SHADOW_VERTEX_COUNT ((SHADOW_LAYER_COUNT + 1) * SHADOW_RAY_COUNT + 1)
+
+// The total number of indices used for drawing the shadow geometry as triangle strips.
+#define SHADOW_INDEX_COUNT (2 * SHADOW_RAY_COUNT + 1 + 2 * (SHADOW_RAY_COUNT + 1) * \
+        SHADOW_LAYER_COUNT)
+
 class ShadowTessellator {
 public:
-    static void tessellateAmbientShadow(const Vector3* casterPolygon, int casterVertexCount,
+    static void tessellateAmbientShadow(const Vector3* casterPolygon,
+            int casterVertexCount, const Vector3& centroid3d,
             VertexBuffer& shadowVertexBuffer);
 
     static void tessellateSpotShadow(const Vector3* casterPolygon, int casterVertexCount,
             const Vector3& lightPosScale, const mat4& receiverTransform,
             int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer);
+
+    static void generateShadowIndices(uint16_t*  shadowIndices);
+
+    static Vector2 centroid2d(const Vector2* poly, int polyLength);
 }; // ShadowTessellator
 
 }; // namespace uirenderer
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 4c2299e..22d735bf 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <utils/Log.h>
 
+#include "ShadowTessellator.h"
 #include "SpotShadow.h"
 #include "Vertex.h"
 
@@ -70,35 +71,6 @@
 }
 
 /**
- * Calculate the centroid of a 2d polygon.
- *
- * @param poly The polygon, which is represented in a Vector2 array.
- * @param polyLength The length of the polygon in terms of number of vertices.
- * @return the centroid of the polygon.
- */
-Vector2 SpotShadow::centroid2d(const Vector2* poly, int polyLength) {
-    double sumx = 0;
-    double sumy = 0;
-    int p1 = polyLength - 1;
-    double area = 0;
-    for (int p2 = 0; p2 < polyLength; p2++) {
-        double x1 = poly[p1].x;
-        double y1 = poly[p1].y;
-        double x2 = poly[p2].x;
-        double y2 = poly[p2].y;
-        double a = (x1 * y2 - x2 * y1);
-        sumx += (x1 + x2) * a;
-        sumy += (y1 + y2) * a;
-        area += a;
-        p1 = p2;
-    }
-
-    double centroidx = sumx / (3 * area);
-    double centroidy = sumy / (3 * area);
-    return Vector2((float)centroidx, (float)centroidy);
-}
-
-/**
  * Sort points by their X coordinates
  *
  * @param points the points as a Vector2 array.
@@ -550,20 +522,17 @@
 * @param lightCenter the center of the light
 * @param lightSize the radius of the light source
 * @param lightVertexCount the vertex counter for the light polygon
-* @param rays the number of vertexes to create along the edges of the shadow
-* @param layers the number of layers of triangles strips to create
-* @param strength the "darkness" of the shadow
 * @param shadowTriangleStrip return an (x,y,alpha) triangle strip representing the shadow. Return
 *                            empty strip if error.
 *
 */
 void SpotShadow::createSpotShadow(const Vector3* poly, int polyLength,
         const Vector3& lightCenter, float lightSize, int lightVertexCount,
-        int rays, int layers, float strength, VertexBuffer& retStrips) {
+        VertexBuffer& retStrips) {
     Vector3 light[lightVertexCount * 3];
     computeLightPolygon(lightVertexCount, lightCenter, lightSize, light);
-    computeSpotShadow(light, lightVertexCount, lightCenter,
-            poly, polyLength, rays, layers, strength, retStrips);
+    computeSpotShadow(light, lightVertexCount, lightCenter, poly, polyLength,
+            retStrips);
 }
 
 /**
@@ -573,15 +542,12 @@
  * @param lightPolyLength number of vertexes of the light source polygon
  * @param poly x,y,z vertexes of a convex polygon that occludes the light source
  * @param polyLength number of vertexes of the occluding polygon
- * @param rays the number of vertexes to create along the edges of the shadow
- * @param layers the number of layers of triangles strips to create
- * @param strength the "darkness" of the shadow
  * @param shadowTriangleStrip return an (x,y,alpha) triangle strip representing the shadow. Return
  *                            empty strip if error.
  */
 void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength,
         const Vector3& lightCenter, const Vector3* poly, int polyLength,
-        int rays, int layers, float strength, VertexBuffer& shadowTriangleStrip) {
+        VertexBuffer& shadowTriangleStrip) {
     // Point clouds for all the shadowed vertices
     Vector2 shadowRegion[lightPolyLength * polyLength];
     // Shadow polygon from one point light.
@@ -671,7 +637,8 @@
 
         // Shrink the centroid's shadow by 10%.
         // TODO: Study the magic number of 10%.
-        Vector2 shadowCentroid = centroid2d(fakeUmbra, polyLength);
+        Vector2 shadowCentroid =
+                ShadowTessellator::centroid2d(fakeUmbra, polyLength);
         for (int i = 0; i < polyLength; i++) {
             fakeUmbra[i] = shadowCentroid * (1.0f - SHADOW_SHRINK_SCALE) +
                     fakeUmbra[i] * SHADOW_SHRINK_SCALE;
@@ -686,7 +653,7 @@
     }
 
     generateTriangleStrip(penumbra, penumbraLength, umbra, umbraLength,
-            rays, layers, strength, shadowTriangleStrip);
+            shadowTriangleStrip);
 }
 
 /**
@@ -696,22 +663,18 @@
  * @param penumbraLength The number of vertexes in the outer polygon
  * @param umbra The inner outer polygon x,y vertexes
  * @param umbraLength The number of vertexes in the inner polygon
- * @param rays The number of points along the polygons to create
- * @param layers The number of layers of triangle strips between the umbra and penumbra
- * @param strength The max alpha of the umbra
  * @param shadowTriangleStrip return an (x,y,alpha) triangle strip representing the shadow. Return
  *                            empty strip if error.
 **/
 void SpotShadow::generateTriangleStrip(const Vector2* penumbra, int penumbraLength,
-        const Vector2* umbra, int umbraLength, int rays, int layers,
-        float strength, VertexBuffer& shadowTriangleStrip) {
+        const Vector2* umbra, int umbraLength, VertexBuffer& shadowTriangleStrip) {
+    const int rays = SHADOW_RAY_COUNT;
+    const int layers = SHADOW_LAYER_COUNT;
 
-    int rings = layers + 1;
-    int size = rays * rings;
-
+    int size = rays * (layers + 1);
     float step = M_PI * 2 / rays;
     // Centroid of the umbra.
-    Vector2 centroid = centroid2d(umbra, umbraLength);
+    Vector2 centroid = ShadowTessellator::centroid2d(umbra, umbraLength);
 #if DEBUG_SHADOW
     ALOGD("centroid2d =  %f , %f", centroid.x, centroid.y);
 #endif
@@ -741,57 +704,29 @@
     int stripSize = getStripSize(rays, layers);
     AlphaVertex* shadowVertices = shadowTriangleStrip.alloc<AlphaVertex>(stripSize);
     int currentIndex = 0;
-    int firstInLayer = 0;
-    // Calculate the vertex values in the penumbra area.
-    for (int r = 0; r < layers; r++) {
-        firstInLayer = currentIndex;
-        for (int i = 0; i < rays; i++) {
-            float dx = sinf(step * i);
-            float dy = cosf(step * i);
 
-            for (int j = r; j < (r + 2); j++) {
-                float layerRatio = j / (float)(rings - 1);
-                float deltaDist = layerRatio * (umbraDistPerRay[i] - penumbraDistPerRay[i]);
-                float currentDist = penumbraDistPerRay[i] + deltaDist;
-                float op = calculateOpacity(layerRatio, deltaDist);
+    // Calculate the vertices (x, y, alpha) in the shadow area.
+    for (int layerIndex = 0; layerIndex <= layers; layerIndex++) {
+        for (int rayIndex = 0; rayIndex < rays; rayIndex++) {
+            float dx = sinf(step * rayIndex);
+            float dy = cosf(step * rayIndex);
+                float layerRatio = layerIndex / (float) layers;
+                float deltaDist = layerRatio *
+                        (umbraDistPerRay[rayIndex] - penumbraDistPerRay[rayIndex]);
+                float currentDist = penumbraDistPerRay[rayIndex] + deltaDist;
+                float op = calculateOpacity(layerRatio);
                 AlphaVertex::set(&shadowVertices[currentIndex++],
-                        dx * currentDist + centroid.x,
-                        dy * currentDist + centroid.y,
-                        layerRatio * op * strength);
-            }
+                        dx * currentDist + centroid.x, dy * currentDist + centroid.y, op);
         }
-
-        // Duplicate the vertices from one layer to another one to make triangle
-        // strip.
-        shadowVertices[currentIndex++] = shadowVertices[firstInLayer + 0];
-        shadowVertices[currentIndex++] = shadowVertices[firstInLayer + 1];
     }
-
-    int lastInPenumbra = currentIndex - 1;
-    shadowVertices[currentIndex++] = shadowVertices[lastInPenumbra];
-
-    // Preallocate the vertices (index as [firstInUmbra - 1]) for jumping from
-    // the penumbra to umbra.
-    currentIndex++;
-    int firstInUmbra = currentIndex;
-
-    // traverse the umbra area in a zig zag pattern for strips.
-    const int innerRingStartIndex = firstInLayer + 1;
-    for (int k = 0; k < rays; k++) {
-        int i = k / 2;
-        if ((k & 1) == 1) {
-            i = rays - i - 1;
-        }
-        // copy already computed values for umbra vertices
-        shadowVertices[currentIndex++] = shadowVertices[innerRingStartIndex + i * 2];
-    }
-
-    // Back fill the one vertex for jumping from penumbra to umbra.
-    shadowVertices[firstInUmbra - 1] = shadowVertices[firstInUmbra];
-
+    // The centroid is in the umbra area, so the opacity is considered as 1.0.
+    AlphaVertex::set(&shadowVertices[currentIndex++], centroid.x, centroid.y, 1.0);
 #if DEBUG_SHADOW
+    if (currentIndex != SHADOW_VERTEX_COUNT) {
+        ALOGE("number of vertex generated for spot shadow is wrong!");
+    }
     for (int i = 0; i < currentIndex; i++) {
-        ALOGD("shadow value: i %d, (x:%f, y:%f, a:%f)", i, shadowVertices[i].x,
+        ALOGD("spot shadow value: i %d, (x:%f, y:%f, a:%f)", i, shadowVertices[i].x,
                 shadowVertices[i].y, shadowVertices[i].alpha);
     }
 #endif
@@ -819,17 +754,15 @@
 }
 
 /**
- * Calculate the opacity according to the distance and falloff ratio.
+ * Calculate the opacity according to the distance. Ideally, the opacity is 1.0
+ * in the umbra area, and fall off to 0.0 till the edge of penumbra area.
  *
- * @param distRatio The distance ratio of current sample between umbra and
- *                  penumbra area.
- * @param deltaDist The distance between current sample to the penumbra area.
+ * @param layerRatio The distance ratio of current sample between umbra and penumbra area.
+ *                   Penumbra edge is 0 and umbra edge is 1.
  * @return The opacity according to the distance between umbra and penumbra.
  */
-float SpotShadow::calculateOpacity(float distRatio, float deltaDist) {
-    // TODO: Experiment on the opacity calculation.
-    float falloffRatio = 1 + deltaDist * deltaDist;
-    return (distRatio + 1 - 1 / falloffRatio) / 2;
+float SpotShadow::calculateOpacity(float layerRatio) {
+    return (layerRatio * layerRatio + layerRatio) / 2.0;
 }
 
 /**
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index a50d110..6727eac 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -28,24 +28,22 @@
 public:
     static void createSpotShadow(const Vector3* poly, int polyLength,
             const Vector3& lightCenter, float lightSize, int lightVertexCount,
-            int rays, int layers, float strength, VertexBuffer& retStrips);
+            VertexBuffer& retStrips);
 
 private:
     static void computeSpotShadow(const Vector3* lightPoly, int lightPolyLength,
             const Vector3& lightCenter, const Vector3* poly, int polyLength,
-            int rays, int layers, float strength, VertexBuffer& retstrips);
+            VertexBuffer& retstrips);
 
     static void computeLightPolygon(int points, const Vector3& lightCenter,
             float size, Vector3* ret);
 
     static int  getStripSize(int rays, int layers);
     static void smoothPolygon(int level, int rays, float* rayDist);
-    static float calculateOpacity(float jf, float deltaDist);
+    static float calculateOpacity(float jf);
     static float rayIntersectPoly(const Vector2* poly, int polyLength,
             const Vector2& point, float dx, float dy);
 
-    static Vector2 centroid2d(const Vector2* poly, int polyLength);
-
     static void xsort(Vector2* points, int pointsLength);
     static int hull(Vector2* points, int pointsLength, Vector2* retPoly);
     static bool ccw(double ax, double ay, double bx, double by, double cx, double cy);
@@ -65,8 +63,7 @@
             double x3, double y3, double x4, double y4, Vector2& ret);
 
     static void generateTriangleStrip(const Vector2* penumbra, int penumbraLength,
-            const Vector2* umbra, int umbraLength, int rays, int layers,
-            float strength, VertexBuffer& retstrips);
+            const Vector2* umbra, int umbraLength, VertexBuffer& retstrips);
 
     static const double EPSILON = 1e-7;
 
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 467f6ca..01d72d1 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -184,7 +184,9 @@
     Mutex::Autolock _l(mLock);
     size_t count = mGarbage.size();
     for (size_t i = 0; i < count; i++) {
-        mCache.remove(mGarbage.itemAt(i));
+        const SkBitmap* bitmap = mGarbage.itemAt(i);
+        mCache.remove(bitmap);
+        delete bitmap;
     }
     mGarbage.clear();
 }
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
index 6011ff0..a7fb0e2 100644
--- a/libs/input/Android.mk
+++ b/libs/input/Android.mk
@@ -31,7 +31,6 @@
 	libinputflinger
 
 LOCAL_C_INCLUDES := \
-    external/skia/include/core \
     frameworks/native/services
 
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index ced3ec9..36778aa 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -28,6 +28,7 @@
 import android.util.Log;
 
 
+import java.lang.SecurityException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -1104,13 +1105,18 @@
      * unless they depend on provider-specific APIs such as
      * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
      *
+     * <p>
+     * Before API version 20, this method would throw {@link SecurityException}
+     * if the location permissions were not sufficient to use the specified
+     * provider.
+     *
      * @param provider the name of the provider
      * @return true if the provider exists and is enabled
      *
      * @throws IllegalArgumentException if provider is null
-     * @throws SecurityException if no suitable permission is present
      */
     public boolean isProviderEnabled(String provider) {
+        // STOPSHIP: finalize API version number in javadoc
         checkProvider(provider);
 
         try {
diff --git a/media/java/android/media/IMediaController.aidl b/media/java/android/media/session/IMediaController.aidl
similarity index 92%
rename from media/java/android/media/IMediaController.aidl
rename to media/java/android/media/session/IMediaController.aidl
index fc3525a..8ca0e45 100644
--- a/media/java/android/media/IMediaController.aidl
+++ b/media/java/android/media/session/IMediaController.aidl
@@ -13,10 +13,10 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.media.session;
 
 import android.content.Intent;
-import android.media.IMediaControllerCallback;
+import android.media.session.IMediaControllerCallback;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.view.KeyEvent;
diff --git a/media/java/android/media/IMediaControllerCallback.aidl b/media/java/android/media/session/IMediaControllerCallback.aidl
similarity index 96%
rename from media/java/android/media/IMediaControllerCallback.aidl
rename to media/java/android/media/session/IMediaControllerCallback.aidl
index b54d0cf..3aa0ee4 100644
--- a/media/java/android/media/IMediaControllerCallback.aidl
+++ b/media/java/android/media/session/IMediaControllerCallback.aidl
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.media.session;
 
 import android.os.Bundle;
 
diff --git a/media/java/android/media/IMediaSession.aidl b/media/java/android/media/session/IMediaSession.aidl
similarity index 92%
rename from media/java/android/media/IMediaSession.aidl
rename to media/java/android/media/session/IMediaSession.aidl
index ed71d78..19f7092 100644
--- a/media/java/android/media/IMediaSession.aidl
+++ b/media/java/android/media/session/IMediaSession.aidl
@@ -13,9 +13,9 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.media.session;
 
-import android.media.IMediaController;
+import android.media.session.IMediaController;
 import android.os.Bundle;
 
 /**
diff --git a/media/java/android/media/IMediaSessionCallback.aidl b/media/java/android/media/session/IMediaSessionCallback.aidl
similarity index 96%
rename from media/java/android/media/IMediaSessionCallback.aidl
rename to media/java/android/media/session/IMediaSessionCallback.aidl
index 3aaf925..eb5f222 100644
--- a/media/java/android/media/IMediaSessionCallback.aidl
+++ b/media/java/android/media/session/IMediaSessionCallback.aidl
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.media.session;
 
 import android.content.Intent;
 import android.os.Bundle;
diff --git a/media/java/android/media/IMediaSessionManager.aidl b/media/java/android/media/session/IMediaSessionManager.aidl
similarity index 86%
rename from media/java/android/media/IMediaSessionManager.aidl
rename to media/java/android/media/session/IMediaSessionManager.aidl
index 8bc0c3b..0b4328e 100644
--- a/media/java/android/media/IMediaSessionManager.aidl
+++ b/media/java/android/media/session/IMediaSessionManager.aidl
@@ -13,10 +13,10 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.media.session;
 
-import android.media.IMediaSession;
-import android.media.IMediaSessionCallback;
+import android.media.session.IMediaSession;
+import android.media.session.IMediaSessionCallback;
 import android.os.Bundle;
 
 /**
diff --git a/media/java/android/media/MediaController.java b/media/java/android/media/session/MediaController.java
similarity index 97%
rename from media/java/android/media/MediaController.java
rename to media/java/android/media/session/MediaController.java
index 1e99942..09de859 100644
--- a/media/java/android/media/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -14,9 +14,13 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.media.session;
 
 import android.content.Intent;
+import android.media.session.IMediaController;
+import android.media.session.IMediaControllerCallback;
+import android.media.MediaMetadataRetriever;
+import android.media.RemoteControlClient;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
diff --git a/media/java/android/media/MediaSession.java b/media/java/android/media/session/MediaSession.java
similarity index 97%
rename from media/java/android/media/MediaSession.java
rename to media/java/android/media/session/MediaSession.java
index 5e5c9fa..1f1533b 100644
--- a/media/java/android/media/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.media.session;
 
 import android.content.Intent;
-import android.media.IMediaSession;
+import android.media.session.IMediaController;
+import android.media.session.IMediaSession;
+import android.media.session.IMediaSessionCallback;
+import android.media.RemoteControlClient;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
diff --git a/media/java/android/media/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
similarity index 96%
rename from media/java/android/media/MediaSessionManager.java
rename to media/java/android/media/session/MediaSessionManager.java
index 90f0071..e3f2d9c 100644
--- a/media/java/android/media/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.media.session;
 
 import android.content.Context;
+import android.media.session.IMediaSessionManager;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
diff --git a/media/java/android/media/MediaSessionToken.aidl b/media/java/android/media/session/MediaSessionToken.aidl
similarity index 95%
rename from media/java/android/media/MediaSessionToken.aidl
rename to media/java/android/media/session/MediaSessionToken.aidl
index e2f1abc..5812682 100644
--- a/media/java/android/media/MediaSessionToken.aidl
+++ b/media/java/android/media/session/MediaSessionToken.aidl
@@ -13,6 +13,6 @@
 ** limitations under the License.
 */
 
-package android.media;
+package android.media.session;
 
 parcelable MediaSessionToken;
diff --git a/media/java/android/media/MediaSessionToken.java b/media/java/android/media/session/MediaSessionToken.java
similarity index 95%
rename from media/java/android/media/MediaSessionToken.java
rename to media/java/android/media/session/MediaSessionToken.java
index 885fda3..dbb4964 100644
--- a/media/java/android/media/MediaSessionToken.java
+++ b/media/java/android/media/session/MediaSessionToken.java
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.media.session;
 
+import android.media.session.IMediaController;
 import android.os.Parcel;
 import android.os.Parcelable;
 
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 51fccd4..35327c0 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -61,8 +61,7 @@
     $(call include-path-for, libhardware)/hardware \
     system/media/camera/include \
     $(PV_INCLUDES) \
-    $(JNI_H_INCLUDE) \
-    $(call include-path-for, corecg graphics)
+    $(JNI_H_INCLUDE)
 
 LOCAL_CFLAGS +=
 
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index f17209f..f3a7ff7 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -21,7 +21,7 @@
 #include <assert.h>
 #include <utils/Log.h>
 #include <utils/threads.h>
-#include <core/SkBitmap.h>
+#include <SkBitmap.h>
 #include <media/IMediaHTTPService.h>
 #include <media/mediametadataretriever.h>
 #include <private/media/VideoFrame.h>
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 6be7fdd..76e8346 100644
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -35,7 +35,6 @@
     $(TOP)/frameworks/base/media/libstagefright/include \
     $(TOP)/frameworks/base/media/libstagefright/rtsp \
     $(JNI_H_INCLUDE) \
-    $(call include-path-for, corecg graphics) \
     $(TOP)/frameworks/native/include/media/editor \
     $(TOP)/frameworks/base/core/jni/mediaeditor \
     $(TOP)/frameworks/av/libvideoeditor/vss/inc \
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index ad874c8..95ae33b 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -34,11 +34,6 @@
 
 LOCAL_C_INCLUDES := \
     $(TOP)/external/jpeg \
-    $(TOP)/external/skia/include/config \
-    $(TOP)/external/skia/include/core \
-    $(TOP)/external/skia/include/images \
-    $(TOP)/external/skia/include/utils \
-    $(TOP)/external/skia/include/effects \
     $(TOP)/frameworks/base/media/libstagefright \
     $(TOP)/frameworks/base/include/ \
     $(TOP)/frameworks/base/ \
diff --git a/media/tests/omxjpegdecoder/StreamSource.h b/media/tests/omxjpegdecoder/StreamSource.h
index 6c34cbd..9807385 100644
--- a/media/tests/omxjpegdecoder/StreamSource.h
+++ b/media/tests/omxjpegdecoder/StreamSource.h
@@ -20,7 +20,7 @@
 
 #include <stdio.h>
 
-#include <core/SkStream.h>
+#include <SkStream.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/threads.h>
diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk
index 8b333e7..3154030 100644
--- a/native/graphics/jni/Android.mk
+++ b/native/graphics/jni/Android.mk
@@ -23,7 +23,6 @@
     libskia
 
 LOCAL_C_INCLUDES += \
-	external/skia/include/core \
 	frameworks/base/native/include \
 	frameworks/base/core/jni/android/graphics
 
diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java
index b6dd9c2..cf09c58 100644
--- a/opengl/java/android/opengl/EGL14.java
+++ b/opengl/java/android/opengl/EGL14.java
@@ -155,12 +155,11 @@
     );
 
     // C function EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id )
-    // TODO Deprecate the eglGetDisplay(int) API method
 
     public static native EGLDisplay eglGetDisplay(
         int display_id
     );
-    // TODO Unhide the eglGetDisplay(long) API method
+
     /**
      * {@hide}
      */
diff --git a/opengl/java/android/opengl/EGLObjectHandle.java b/opengl/java/android/opengl/EGLObjectHandle.java
index e6e3976..f961eb7 100644
--- a/opengl/java/android/opengl/EGLObjectHandle.java
+++ b/opengl/java/android/opengl/EGLObjectHandle.java
@@ -24,18 +24,28 @@
 public abstract class EGLObjectHandle {
     private final long mHandle;
 
-    // TODO Deprecate EGLObjectHandle(int) method
+    /**
+     * @deprecated Use {@link #EGLObjectHandle(long)} instead. Handles
+     *     on 64 bit platforms will be wider than java ints.
+     */
+    @Deprecated
     protected EGLObjectHandle(int handle) {
         mHandle = handle;
     }
-    // TODO Unhide the EGLObjectHandle(long) method
-    /**
-     * {@hide}
-     */
     protected EGLObjectHandle(long handle) {
         mHandle = handle;
     }
-    // TODO Deprecate getHandle() method in favor of getNativeHandle()
+    /**
+     * @deprecated Use {@link #getNativeHandle()} instead. Handles on
+     *     64 bit platforms will be wider than java ints.
+     */
+    @Deprecated
+    public int getHandle() {
+        if ((mHandle & 0xffffffffL) != mHandle) {
+            throw new UnsupportedOperationException();
+        }
+        return (int)mHandle;
+    }
     /**
      * Returns the native handle of the wrapped EGL object. This handle can be
      * cast to the corresponding native type on the native side.
@@ -44,17 +54,6 @@
      *
      * @return the native handle of the wrapped EGL object.
      */
-    public int getHandle() {
-        if ((mHandle & 0xffffffffL) != mHandle) {
-            throw new UnsupportedOperationException();
-        }
-        return (int)mHandle;
-    }
-
-    // TODO Unhide getNativeHandle() method
-    /**
-     * {@hide}
-     */
     public long getNativeHandle() {
         return mHandle;
     }
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index 1f2b5fb..5b08674 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -16,7 +16,8 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files) \
+                   $(call all-proto-files-under,src)
 
 LOCAL_PACKAGE_NAME := Keyguard
 
@@ -26,6 +27,9 @@
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
+
 include $(BUILD_PACKAGE)
 
 #include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index fd4cf78..ebe678e 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -27,7 +27,7 @@
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"የይለፍ ቃል ለመተየብ ንካ"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ለመክፈት የይለፍ ቃል ተይብ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ለመክፈት ፒን ተይብ"</string>
-    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ PIN ኮድ።"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ ፒን  ኮድ።"</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"ለመክፈት፣ምናሌ ተጫን ከዛ 0"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"የመጨረሻውን  የገጽ ክፈት ሙከራዎችን አልፏል"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"ባትሪ ሞልቷል"</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index 43165eb..8738288 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -21,11 +21,11 @@
 
 import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.analytics.KeyguardAnalytics;
 
 import org.xmlpull.v1.XmlPullParser;
 
 import android.app.ActivityManager;
-import android.appwidget.AppWidgetManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -71,10 +71,12 @@
 
     // Timeout used for keypresses
     static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
+    private static final boolean ENABLE_SIMPLE_KEYGUARD = false;
 
     private final Context mContext;
     private final ViewManager mViewManager;
     private final KeyguardViewMediator.ViewMediatorCallback mViewMediatorCallback;
+    private final KeyguardAnalytics.Callback mAnalyticsCallback;
 
     private WindowManager.LayoutParams mWindowLayoutParams;
     private boolean mNeedsInput = false;
@@ -106,11 +108,12 @@
      */
     public KeyguardViewManager(Context context, ViewManager viewManager,
             KeyguardViewMediator.ViewMediatorCallback callback,
-            LockPatternUtils lockPatternUtils) {
+            LockPatternUtils lockPatternUtils, KeyguardAnalytics.Callback analyticsCallback) {
         mContext = context;
         mViewManager = viewManager;
         mViewMediatorCallback = callback;
         mLockPatternUtils = lockPatternUtils;
+        mAnalyticsCallback = analyticsCallback;
     }
 
     /**
@@ -119,6 +122,9 @@
      */
     public synchronized void show(Bundle options) {
         if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
+        if (mAnalyticsCallback != null) {
+            mAnalyticsCallback.onShow();
+        }
 
         boolean enableScreenRotation = shouldEnableScreenRotation();
 
@@ -261,6 +267,15 @@
             }
             return super.dispatchKeyEvent(event);
         }
+
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent ev) {
+            boolean result = false;
+            if (mAnalyticsCallback != null) {
+                result = mAnalyticsCallback.onTouchEvent(ev, getWidth(), getHeight()) || result;
+            }
+            return super.dispatchTouchEvent(ev) || result;
+        }
     }
 
     SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>();
@@ -312,7 +327,7 @@
         if (force || mKeyguardView == null) {
             mKeyguardHost.setCustomBackground(null);
             mKeyguardHost.removeAllViews();
-            int layout = allowNotificationsOnSecureKeyguard()
+            int layout = (allowNotificationsOnSecureKeyguard() && ENABLE_SIMPLE_KEYGUARD)
                     ? R.layout.keyguard_simple_host_view
                     : R.layout.keyguard_host_view;
             if (mCurrentLayout != layout) {
@@ -472,6 +487,9 @@
                 Slog.w(TAG, "Exception calling onShown():", e);
             }
         }
+        if (mAnalyticsCallback != null) {
+            mAnalyticsCallback.onScreenOn();
+        }
     }
 
     public synchronized void verifyUnlock() {
@@ -486,6 +504,10 @@
     public synchronized void hide() {
         if (DEBUG) Log.d(TAG, "hide()");
 
+        if (mAnalyticsCallback != null) {
+            mAnalyticsCallback.onHide();
+        }
+
         if (mKeyguardHost != null) {
             mKeyguardHost.setVisibility(View.GONE);
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index 151177e..31e806c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -19,6 +19,7 @@
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardShowCallback;
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static com.android.keyguard.analytics.KeyguardAnalytics.SessionTypeAdapter;
 
 import android.app.Activity;
 import android.app.ActivityManagerNative;
@@ -33,6 +34,7 @@
 import android.content.IntentFilter;
 import android.media.AudioManager;
 import android.media.SoundPool;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -54,6 +56,10 @@
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.analytics.Session;
+import com.android.keyguard.analytics.KeyguardAnalytics;
+
+import java.io.File;
 
 
 /**
@@ -100,6 +106,7 @@
 public class KeyguardViewMediator {
     private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
     final static boolean DEBUG = false;
+    private static final boolean ENABLE_ANALYTICS = Build.IS_DEBUGGABLE;
     private final static boolean DBG_WAKE = false;
 
     private final static String TAG = "KeyguardViewMediator";
@@ -161,6 +168,11 @@
      */
     private static final boolean ALLOW_NOTIFICATIONS_DEFAULT = false;
 
+    /**
+     * Secure setting whether analytics are collected on the keyguard.
+     */
+    private static final String KEYGUARD_ANALYTICS_SETTING = "keyguard_analytics";
+
     /** The stream type that the lock sounds are tied to. */
     private int mMasterStreamType;
 
@@ -194,6 +206,8 @@
 
     private KeyguardViewManager mKeyguardViewManager;
 
+    private final KeyguardAnalytics mKeyguardAnalytics;
+
     // these are protected by synchronized (this)
 
     /**
@@ -528,12 +542,25 @@
                 && !mLockPatternUtils.isLockScreenDisabled();
 
         WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-
-        mKeyguardViewManager = new KeyguardViewManager(context, wm, mViewMediatorCallback,
-                mLockPatternUtils);
-
         final ContentResolver cr = mContext.getContentResolver();
 
+        if (ENABLE_ANALYTICS && !LockPatternUtils.isSafeModeEnabled() &&
+                Settings.Secure.getInt(cr, KEYGUARD_ANALYTICS_SETTING, 0) == 1) {
+            mKeyguardAnalytics = new KeyguardAnalytics(context, new SessionTypeAdapter() {
+
+                @Override
+                public int getSessionType() {
+                    return mLockPatternUtils.isSecure() ? Session.TYPE_KEYGUARD_SECURE
+                            : Session.TYPE_KEYGUARD_INSECURE;
+                }
+            }, new File(mContext.getCacheDir(), "keyguard_analytics.bin"));
+        } else {
+            mKeyguardAnalytics = null;
+        }
+        mKeyguardViewManager = new KeyguardViewManager(context, wm, mViewMediatorCallback,
+                mLockPatternUtils,
+                mKeyguardAnalytics != null ? mKeyguardAnalytics.getCallback() : null);
+
         mScreenOn = mPM.isScreenOn();
 
         mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
@@ -631,6 +658,9 @@
             } else {
                 doKeyguardLocked(null);
             }
+            if (ENABLE_ANALYTICS && mKeyguardAnalytics != null) {
+                mKeyguardAnalytics.getCallback().onScreenOff();
+            }
         }
         KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurndOff(why);
     }
@@ -869,6 +899,9 @@
                 updateActivityLockScreenState();
                 adjustStatusBarLocked();
             }
+            if (ENABLE_ANALYTICS && mKeyguardAnalytics != null) {
+                mKeyguardAnalytics.getCallback().onSetHidden(isHidden);
+            }
         }
     }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java b/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java
new file mode 100644
index 0000000..55750cc
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/analytics/KeyguardAnalytics.java
@@ -0,0 +1,278 @@
+/*
+ * 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.keyguard.analytics;
+
+import com.google.protobuf.nano.CodedOutputByteBufferNano;
+import com.google.protobuf.nano.MessageNano;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.AsyncTask;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Tracks sessions, touch and sensor events in Keyguard.
+ *
+ * A session starts when the user is presented with the Keyguard and ends when the Keyguard is no
+ * longer visible to the user.
+ */
+public class KeyguardAnalytics implements SensorEventListener {
+
+    private static final boolean DEBUG = false;
+    private static final String TAG = "KeyguardAnalytics";
+    private static final long TIMEOUT_MILLIS = 11000; // 11 seconds.
+
+    private static final int[] SENSORS = new int[] {
+            Sensor.TYPE_ACCELEROMETER,
+            Sensor.TYPE_GYROSCOPE,
+            Sensor.TYPE_PROXIMITY,
+            Sensor.TYPE_LIGHT,
+            Sensor.TYPE_ROTATION_VECTOR,
+    };
+
+    private Session mCurrentSession = null;
+    // Err on the side of caution, so logging is not started after a crash even tough the screen
+    // is off.
+    private boolean mScreenOn = false;
+    private boolean mHidden = false;
+
+    private final SensorManager mSensorManager;
+    private final SessionTypeAdapter mSessionTypeAdapter;
+    private final File mAnalyticsFile;
+
+    public KeyguardAnalytics(Context context, SessionTypeAdapter sessionTypeAdapter,
+            File analyticsFile) {
+        mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+        mSessionTypeAdapter = sessionTypeAdapter;
+        mAnalyticsFile = analyticsFile;
+    }
+
+    public Callback getCallback() {
+        return mCallback;
+    }
+
+    public interface Callback {
+        public void onShow();
+        public void onHide();
+        public void onScreenOn();
+        public void onScreenOff();
+        public boolean onTouchEvent(MotionEvent ev, int width, int height);
+        public void onSetHidden(boolean hidden);
+    }
+
+    public interface SessionTypeAdapter {
+        public int getSessionType();
+    }
+
+    private void sessionEntrypoint() {
+        if (mCurrentSession == null && mScreenOn && !mHidden) {
+            onSessionStart();
+        }
+    }
+
+    private void sessionExitpoint(int result) {
+        if (mCurrentSession != null) {
+            onSessionEnd(result);
+        }
+    }
+
+    private void onSessionStart() {
+        int type = mSessionTypeAdapter.getSessionType();
+        mCurrentSession = new Session(System.currentTimeMillis(), System.nanoTime(), type);
+        if (type == Session.TYPE_KEYGUARD_SECURE) {
+            mCurrentSession.setRedactTouchEvents();
+        }
+        for (int sensorType : SENSORS) {
+            Sensor s = mSensorManager.getDefaultSensor(sensorType);
+            if (s != null) {
+                mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
+            }
+        }
+        if (DEBUG) {
+            Log.d(TAG, "onSessionStart()");
+        }
+    }
+
+    private void onSessionEnd(int result) {
+        if (DEBUG) {
+            Log.d(TAG, String.format("onSessionEnd(success=%d)", result));
+        }
+        mSensorManager.unregisterListener(this);
+
+        Session session = mCurrentSession;
+        mCurrentSession = null;
+
+        session.end(System.currentTimeMillis(), result);
+        queueSession(session);
+    }
+
+    private void queueSession(final Session currentSession) {
+        if (DEBUG) {
+            Log.i(TAG, "Saving session.");
+        }
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                try {
+                    byte[] b = writeDelimitedProto(currentSession.toProto());
+                    OutputStream os = new FileOutputStream(mAnalyticsFile, true /* append */);
+                    if (DEBUG) {
+                        Log.d(TAG, String.format("Serialized size: %d kB.", b.length / 1024));
+                    }
+                    try {
+                        os.write(b);
+                        os.flush();
+                    } finally {
+                        try {
+                            os.close();
+                        } catch (IOException e) {
+                            Log.e(TAG, "Exception while closing file", e);
+                        }
+                    }
+                } catch (IOException e) {
+                    Log.e(TAG, "Exception while writing file", e);
+                }
+                return null;
+            }
+
+            private byte[] writeDelimitedProto(MessageNano proto)
+                    throws IOException {
+                byte[] result = new byte[CodedOutputByteBufferNano.computeMessageSizeNoTag(proto)];
+                CodedOutputByteBufferNano ob = CodedOutputByteBufferNano.newInstance(result);
+                ob.writeMessageNoTag(proto);
+                ob.checkNoSpaceLeft();
+                return result;
+            }
+        }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+    }
+
+    @Override
+    public synchronized void onSensorChanged(SensorEvent event) {
+        if (false) {
+            Log.v(TAG, String.format(
+                    "onSensorChanged(name=%s, values[0]=%f)",
+                    event.sensor.getName(), event.values[0]));
+        }
+        if (mCurrentSession != null) {
+            mCurrentSession.addSensorEvent(event, System.nanoTime());
+            enforceTimeout();
+        }
+    }
+
+    private void enforceTimeout() {
+        if (System.currentTimeMillis() - mCurrentSession.getStartTimestampMillis()
+                > TIMEOUT_MILLIS) {
+            onSessionEnd(Session.RESULT_UNKNOWN);
+            if (DEBUG) {
+                Log.i(TAG, "Analytics timed out.");
+            }
+        }
+    }
+
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+    }
+
+    private final Callback mCallback = new Callback() {
+        @Override
+        public void onShow() {
+            if (DEBUG) {
+                Log.d(TAG, "onShow()");
+            }
+            synchronized (KeyguardAnalytics.this) {
+                sessionEntrypoint();
+            }
+        }
+
+        @Override
+        public void onHide() {
+            if (DEBUG) {
+                Log.d(TAG, "onHide()");
+            }
+            synchronized (KeyguardAnalytics.this) {
+                sessionExitpoint(Session.RESULT_SUCCESS);
+            }
+        }
+
+        @Override
+        public void onScreenOn() {
+            if (DEBUG) {
+                Log.d(TAG, "onScreenOn()");
+            }
+            synchronized (KeyguardAnalytics.this) {
+                mScreenOn = true;
+                sessionEntrypoint();
+            }
+        }
+
+        @Override
+        public void onScreenOff() {
+            if (DEBUG) {
+                Log.d(TAG, "onScreenOff()");
+            }
+            synchronized (KeyguardAnalytics.this) {
+                mScreenOn = false;
+                sessionExitpoint(Session.RESULT_FAILURE);
+            }
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent ev, int width, int height) {
+            if (DEBUG) {
+                Log.v(TAG, "onTouchEvent(ev.action="
+                        + MotionEvent.actionToString(ev.getAction()) + ")");
+            }
+            synchronized (KeyguardAnalytics.this) {
+                if (mCurrentSession != null) {
+                    mCurrentSession.addMotionEvent(ev);
+                    mCurrentSession.setTouchArea(width, height);
+                    enforceTimeout();
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public void onSetHidden(boolean hidden) {
+            synchronized (KeyguardAnalytics.this) {
+                if (hidden != mHidden) {
+                    if (DEBUG) {
+                        Log.d(TAG, "onSetHidden(" + hidden + ")");
+                    }
+                    mHidden = hidden;
+                    if (hidden) {
+                        // Could have gone to camera on purpose / by falsing or an app could have
+                        // launched on top of the lockscreen.
+                        sessionExitpoint(Session.RESULT_UNKNOWN);
+                    } else {
+                        sessionEntrypoint();
+                    }
+                }
+            }
+        }
+    };
+
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/analytics/PointerTracker.java b/packages/Keyguard/src/com/android/keyguard/analytics/PointerTracker.java
new file mode 100644
index 0000000..e68f751
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/analytics/PointerTracker.java
@@ -0,0 +1,109 @@
+/*
+ * 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.keyguard.analytics;
+
+import android.graphics.RectF;
+import android.util.FloatMath;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.android.keyguard.analytics.KeyguardAnalyticsProtos.Session.TouchEvent.BoundingBox;
+
+/**
+ * Takes motion events and tracks the length and bounding box of each pointer gesture as well as
+ * the bounding box of the whole gesture.
+ */
+public class PointerTracker {
+    private SparseArray<Pointer> mPointerInfoMap = new SparseArray<Pointer>();
+    private RectF mTotalBoundingBox = new RectF();
+
+    public void addMotionEvent(MotionEvent ev) {
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            float x = ev.getX();
+            float y = ev.getY();
+            mTotalBoundingBox.set(x, y, x, y);
+        }
+        for (int i = 0; i < ev.getPointerCount(); i++) {
+            int id = ev.getPointerId(i);
+            Pointer pointer = getPointer(id);
+            float x = ev.getX(i);
+            float y = ev.getY(i);
+            boolean down = ev.getActionMasked() == MotionEvent.ACTION_DOWN
+                    || (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
+                            && ev.getActionIndex() == i);
+            pointer.addPoint(x, y, down);
+            mTotalBoundingBox.union(x, y);
+        }
+    }
+
+    public float getPointerLength(int id) {
+        return getPointer(id).length;
+    }
+
+    public BoundingBox getBoundingBox() {
+        return boundingBoxFromRect(mTotalBoundingBox);
+    }
+
+    public BoundingBox getPointerBoundingBox(int id) {
+        return boundingBoxFromRect(getPointer(id).boundingBox);
+    }
+
+    private BoundingBox boundingBoxFromRect(RectF f) {
+        BoundingBox bb = new BoundingBox();
+        bb.setHeight(f.height());
+        bb.setWidth(f.width());
+        return bb;
+    }
+
+    private Pointer getPointer(int id) {
+        Pointer p = mPointerInfoMap.get(id);
+        if (p == null) {
+            p = new Pointer();
+            mPointerInfoMap.put(id, p);
+        }
+        return p;
+    }
+
+    private static class Pointer {
+        public float length;
+        public final RectF boundingBox = new RectF();
+
+        private float mLastX;
+        private float mLastY;
+
+        public void addPoint(float x, float y, boolean down) {
+            float deltaX;
+            float deltaY;
+            if (down) {
+                boundingBox.set(x, y, x, y);
+                length = 0f;
+                deltaX = 0;
+                deltaY = 0;
+            } else {
+                deltaX = x - mLastX;
+                deltaY = y - mLastY;
+            }
+            mLastX = x;
+            mLastY = y;
+            length += FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY);
+            boundingBox.union(x, y);
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/analytics/Session.java b/packages/Keyguard/src/com/android/keyguard/analytics/Session.java
new file mode 100644
index 0000000..05f9165
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/analytics/Session.java
@@ -0,0 +1,220 @@
+/*
+ * 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.keyguard.analytics;
+
+import android.os.Build;
+import android.util.Slog;
+import android.view.MotionEvent;
+
+import java.util.ArrayList;
+
+import static com.android.keyguard.analytics.KeyguardAnalyticsProtos.Session.SensorEvent;
+import static com.android.keyguard.analytics.KeyguardAnalyticsProtos.Session.TouchEvent;
+
+/**
+ * Records data about one keyguard session.
+ *
+ * The recorded data contains start and end of the session, whether it unlocked the device
+ * successfully, sensor data and touch data.
+ *
+ * If the keyguard is secure, the recorded touch data will correlate or contain the user pattern or
+ * PIN. If this is not desired, the touch coordinates can be redacted before serialization.
+ */
+public class Session {
+
+    private static final String TAG = "KeyguardAnalytics";
+    private static final boolean DEBUG = false;
+
+    /**
+     * The user has failed to unlock the device in this session.
+     */
+    public static final int RESULT_FAILURE = KeyguardAnalyticsProtos.Session.FAILURE;
+    /**
+     * The user has succeeded in unlocking the device in this session.
+     */
+    public static final int RESULT_SUCCESS = KeyguardAnalyticsProtos.Session.SUCCESS;
+
+    /**
+     * It is unknown how the session with the keyguard ended.
+     */
+    public static final int RESULT_UNKNOWN = KeyguardAnalyticsProtos.Session.UNKNOWN;
+
+    /**
+     * This session took place on an insecure keyguard.
+     */
+    public static final int TYPE_KEYGUARD_INSECURE
+            = KeyguardAnalyticsProtos.Session.KEYGUARD_INSECURE;
+
+    /**
+     * This session took place on an secure keyguard.
+     */
+    public static final int TYPE_KEYGUARD_SECURE
+            = KeyguardAnalyticsProtos.Session.KEYGUARD_SECURE;
+
+    /**
+     * This session took place during a fake wake up of the device.
+     */
+    public static final int TYPE_RANDOM_WAKEUP = KeyguardAnalyticsProtos.Session.RANDOM_WAKEUP;
+
+
+    private final PointerTracker mPointerTracker = new PointerTracker();
+
+    private final long mStartTimestampMillis;
+    private final long mStartSystemTimeNanos;
+    private final int mType;
+
+    private boolean mRedactTouchEvents;
+    private ArrayList<TouchEvent> mMotionEvents = new ArrayList<TouchEvent>(200);
+    private ArrayList<SensorEvent> mSensorEvents = new ArrayList<SensorEvent>(600);
+    private int mTouchAreaHeight;
+    private int mTouchAreaWidth;
+
+    private long mEndTimestampMillis;
+    private int mResult;
+    private boolean mEnded;
+
+    public Session(long startTimestampMillis, long startSystemTimeNanos, int type) {
+        mStartTimestampMillis = startTimestampMillis;
+        mStartSystemTimeNanos = startSystemTimeNanos;
+        mType = type;
+    }
+
+    public void end(long endTimestampMillis, int result) {
+        mEnded = true;
+        mEndTimestampMillis = endTimestampMillis;
+        mResult = result;
+    }
+
+    public void addMotionEvent(MotionEvent motionEvent) {
+        if (mEnded) {
+            return;
+        }
+        mPointerTracker.addMotionEvent(motionEvent);
+        mMotionEvents.add(protoFromMotionEvent(motionEvent));
+    }
+
+    public void addSensorEvent(android.hardware.SensorEvent eventOrig, long systemTimeNanos) {
+        if (mEnded) {
+            return;
+        }
+        SensorEvent event = protoFromSensorEvent(eventOrig, systemTimeNanos);
+        mSensorEvents.add(event);
+        if (DEBUG) {
+            Slog.v(TAG, String.format("addSensorEvent(name=%s, values[0]=%f",
+                    event.getType(), event.values[0]));
+        }
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("Session{");
+        sb.append("mType=").append(mType);
+        sb.append(", mStartTimestampMillis=").append(mStartTimestampMillis);
+        sb.append(", mStartSystemTimeNanos=").append(mStartSystemTimeNanos);
+        sb.append(", mEndTimestampMillis=").append(mEndTimestampMillis);
+        sb.append(", mResult=").append(mResult);
+        sb.append(", mRedactTouchEvents=").append(mRedactTouchEvents);
+        sb.append(", mTouchAreaHeight=").append(mTouchAreaHeight);
+        sb.append(", mTouchAreaWidth=").append(mTouchAreaWidth);
+        sb.append(", mMotionEvents=[size=").append(mMotionEvents.size()).append("]");
+        sb.append(", mSensorEvents=[size=").append(mSensorEvents.size()).append("]");
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public KeyguardAnalyticsProtos.Session toProto() {
+        KeyguardAnalyticsProtos.Session proto = new KeyguardAnalyticsProtos.Session();
+        proto.setStartTimestampMillis(mStartTimestampMillis);
+        proto.setDurationMillis(mEndTimestampMillis - mStartTimestampMillis);
+        proto.setBuild(Build.FINGERPRINT);
+        proto.setResult(mResult);
+        proto.sensorEvents = mSensorEvents.toArray(proto.sensorEvents);
+        proto.touchEvents = mMotionEvents.toArray(proto.touchEvents);
+        proto.setTouchAreaWidth(mTouchAreaWidth);
+        proto.setTouchAreaHeight(mTouchAreaHeight);
+        proto.setType(mType);
+        if (mRedactTouchEvents) {
+            redactTouchEvents(proto.touchEvents);
+        }
+        return proto;
+    }
+
+    private void redactTouchEvents(TouchEvent[] touchEvents) {
+        for (int i = 0; i < touchEvents.length; i++) {
+            TouchEvent t = touchEvents[i];
+            for (int j = 0; j < t.pointers.length; j++) {
+                TouchEvent.Pointer p = t.pointers[j];
+                p.clearX();
+                p.clearY();
+            }
+            t.setRedacted(true);
+        }
+    }
+
+    private SensorEvent protoFromSensorEvent(android.hardware.SensorEvent ev, long sysTimeNanos) {
+        SensorEvent proto = new SensorEvent();
+        proto.setType(ev.sensor.getType());
+        proto.setTimeOffsetNanos(sysTimeNanos - mStartSystemTimeNanos);
+        proto.setTimestamp(ev.timestamp);
+        proto.values = ev.values.clone();
+        return proto;
+    }
+
+    private TouchEvent protoFromMotionEvent(MotionEvent ev) {
+        int count = ev.getPointerCount();
+        TouchEvent proto = new TouchEvent();
+        proto.setTimeOffsetNanos(ev.getEventTimeNano() - mStartSystemTimeNanos);
+        proto.setAction(ev.getActionMasked());
+        proto.setActionIndex(ev.getActionIndex());
+        proto.pointers = new TouchEvent.Pointer[count];
+        for (int i = 0; i < count; i++) {
+            TouchEvent.Pointer p = new TouchEvent.Pointer();
+            p.setX(ev.getX(i));
+            p.setY(ev.getY(i));
+            p.setSize(ev.getSize(i));
+            p.setPressure(ev.getPressure(i));
+            p.setId(ev.getPointerId(i));
+            proto.pointers[i] = p;
+            if ((ev.getActionMasked() == MotionEvent.ACTION_POINTER_UP && ev.getActionIndex() == i)
+                    || ev.getActionMasked() == MotionEvent.ACTION_UP) {
+                p.boundingBox = mPointerTracker.getPointerBoundingBox(p.getId());
+                p.setLength(mPointerTracker.getPointerLength(p.getId()));
+            }
+        }
+        if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+            proto.boundingBox = mPointerTracker.getBoundingBox();
+        }
+        return proto;
+    }
+
+    /**
+     * Discards the x / y coordinates of the touch events on serialization. Retained are the
+     * size of the individual and overall bounding boxes and the length of each pointer's gesture.
+     */
+    public void setRedactTouchEvents() {
+        mRedactTouchEvents = true;
+    }
+
+    public void setTouchArea(int width, int height) {
+        mTouchAreaWidth = width;
+        mTouchAreaHeight = height;
+    }
+
+    public long getStartTimestampMillis() {
+        return mStartTimestampMillis;
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/analytics/keyguard_analytics.proto b/packages/Keyguard/src/com/android/keyguard/analytics/keyguard_analytics.proto
new file mode 100644
index 0000000..68b1590
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/analytics/keyguard_analytics.proto
@@ -0,0 +1,102 @@
+/*
+ * 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
+ */
+
+syntax = "proto2";
+
+package keyguard;
+
+option java_package = "com.android.keyguard.analytics";
+option java_outer_classname = "KeyguardAnalyticsProtos";
+
+message Session {
+    message TouchEvent {
+        message BoundingBox {
+            optional float width = 1;
+            optional float height = 2;
+        }
+
+        enum Action {
+            // Keep in sync with MotionEvent.
+            DOWN = 0;
+            UP = 1;
+            MOVE = 2;
+            CANCEL = 3;
+            OUTSIDE = 4;
+            POINTER_DOWN = 5;
+            POINTER_UP = 6;
+        }
+
+        message Pointer {
+            optional float x = 1;
+            optional float y = 2;
+            optional float size = 3;
+            optional float pressure = 4;
+            optional int32 id = 5;
+            optional float length = 6;
+            // Bounding box of the pointer. Only set on UP or POINTER_UP event of this pointer.
+            optional BoundingBox boundingBox = 7;
+        }
+
+        optional uint64 timeOffsetNanos = 1;
+        optional Action action = 2;
+        optional int32 actionIndex = 3;
+        repeated Pointer pointers = 4;
+        /* If true, the the x / y coordinates of the touch events were redacted. Retained are the
+           size of the individual and overall bounding boxes and the length of each pointer's
+           gesture. */
+        optional bool redacted = 5;
+        // Bounding box of the whole gesture. Only set on UP event.
+        optional BoundingBox boundingBox = 6;
+    }
+
+    message SensorEvent {
+        enum Type {
+            ACCELEROMETER = 1;
+            GYROSCOPE = 4;
+            LIGHT = 5;
+            PROXIMITY = 8;
+            ROTATION_VECTOR = 11;
+        }
+
+        optional Type type = 1;
+        optional uint64 timeOffsetNanos = 2;
+        repeated float values = 3;
+        optional uint64 timestamp = 4;
+    }
+
+    enum Result {
+        FAILURE = 0;
+        SUCCESS = 1;
+        UNKNOWN = 2;
+    }
+
+    enum Type {
+        KEYGUARD_INSECURE = 0;
+        KEYGUARD_SECURE = 1;
+        RANDOM_WAKEUP = 2;
+    }
+
+    optional uint64 startTimestampMillis = 1;
+    optional uint64 durationMillis = 2;
+    optional string build = 3;
+    optional Result result = 4;
+    repeated TouchEvent touchEvents = 5;
+    repeated SensorEvent sensorEvents = 6;
+
+    optional int32 touchAreaWidth = 9;
+    optional int32 touchAreaHeight = 10;
+    optional Type type = 11;
+}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 7410b9d..59b486f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -186,4 +186,7 @@
     <!-- Default for Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1==on -->
     <integer name="def_lock_screen_show_notifications">1</integer>
 
+    <!-- Default for Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1==on -->
+    <integer name="def_heads_up_enabled">1</integer>
+
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b546689..55d7def 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -69,7 +69,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 99;
+    private static final int DATABASE_VERSION = 100;
 
     private Context mContext;
     private int mUserHandle;
@@ -1574,6 +1574,24 @@
             upgradeVersion = 99;
         }
 
+        if (upgradeVersion == 99) {
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                SQLiteStatement stmt = null;
+                try {
+                    stmt = db.compileStatement("INSERT OR REPLACE INTO global(name,value)"
+                            + " VALUES(?,?);");
+                    loadIntegerSetting(stmt, Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+                            R.integer.def_heads_up_enabled);
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                    if (stmt != null) stmt.close();
+                }
+            }
+            upgradeVersion = 100;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
diff --git a/packages/SystemUI/res/anim/heads_up_exit.xml b/packages/SystemUI/res/anim/heads_up_exit.xml
index 05c144a..2cad8f6 100644
--- a/packages/SystemUI/res/anim/heads_up_exit.xml
+++ b/packages/SystemUI/res/anim/heads_up_exit.xml
@@ -1,13 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         >
-    <scale
-        android:interpolator="@android:interpolator/accelerate_quad"
-        android:fromXScale="1.0" android:toXScale="0.7"
-        android:fromYScale="1.0" android:toYScale="0.7"
-        android:pivotX="50%" android:pivotY="50%"
-        android:duration="@android:integer/config_shortAnimTime" />
-    <alpha 
+    <translate
+            android:interpolator="@android:interpolator/overshoot"
+            android:fromYDelta="0" android:toYDelta="-50%"
+            android:duration="@android:integer/config_shortAnimTime" />
+    <alpha
         android:interpolator="@android:interpolator/accelerate_quad"
         android:fromAlpha="1.0" android:toAlpha="0.0"
         android:duration="@android:integer/config_shortAnimTime" />
diff --git a/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png
deleted file mode 100644
index 3b952d0..0000000
--- a/packages/SystemUI/res/drawable-hdpi/heads_up_window_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png
new file mode 100644
index 0000000..267e7ba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png
new file mode 100644
index 0000000..fa23e85
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png
new file mode 100644
index 0000000..aa8635c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png
deleted file mode 100644
index a0ab991..0000000
--- a/packages/SystemUI/res/drawable-mdpi/heads_up_window_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png
new file mode 100644
index 0000000..db51f6b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png
new file mode 100644
index 0000000..b0185a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png
new file mode 100644
index 0000000..949ab10
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png
index 6002cfb..31eb8f7 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/heads_up_window_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png
index 586a738..c76d0e1 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-xhdpi/heads_up_window_bg.9.png
deleted file mode 100644
index 42e5593..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/heads_up_window_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png
new file mode 100644
index 0000000..8d22ce2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png
new file mode 100644
index 0000000..7f7cb63
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png
new file mode 100644
index 0000000..abdeb3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png
deleted file mode 100644
index 586a738..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png
new file mode 100644
index 0000000..29fb50f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png
new file mode 100644
index 0000000..afe85b4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png
new file mode 100644
index 0000000..5e5053f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml b/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml
deleted file mode 100644
index 59d9fcf..0000000
--- a/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-          android:exitFadeDuration="@android:integer/config_mediumAnimTime">
-    <item android:state_pressed="true"
-          android:drawable="@drawable/heads_up_notification_bg_pressed" />
-</selector>
diff --git a/packages/SystemUI/res/layout-sw600dp/heads_up.xml b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
new file mode 100644
index 0000000..71f7c21
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
@@ -0,0 +1,31 @@
+<?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.
+*/
+-->
+<com.android.systemui.statusbar.policy.HeadsUpNotificationView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    >
+    <FrameLayout
+        android:id="@+id/content_holder"
+        android:layout_height="wrap_content"
+        android:layout_width="@dimen/notification_panel_width"
+        android:layout_marginStart="@dimen/notification_panel_margin_left"
+        android:background="@drawable/heads_up_window_bg"
+        />
+</com.android.systemui.statusbar.policy.HeadsUpNotificationView>
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index 564dc51..3a58b84 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -17,25 +17,11 @@
 ** limitations under the License.
 */
 -->
-
-<!--    android:background="@drawable/status_bar_closed_default_background" -->
 <com.android.systemui.statusbar.policy.HeadsUpNotificationView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:orientation="vertical"
-    >
-    <FrameLayout
-            android:layout_height="wrap_content"
-            android:layout_width="@dimen/notification_panel_width"
-            android:id="@+id/content_slider"
-            android:layout_marginStart="@dimen/notification_panel_margin_left"
-            >
-        <FrameLayout
-                android:layout_height="wrap_content"
-                android:layout_width="match_parent"
-                android:id="@+id/content_holder"
-                android:background="@drawable/heads_up_window_bg"
-                />
-    </FrameLayout>
-</com.android.systemui.statusbar.policy.HeadsUpNotificationView>
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_height="wrap_content"
+        android:layout_width="@dimen/notification_panel_width"
+        android:id="@+id/content_holder"
+        android:layout_marginStart="@dimen/notification_panel_margin_left"
+        android:background="@drawable/notification_panel_bg"
+        />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index eb66908..ea6be1b 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -62,7 +62,11 @@
                 android:src="@drawable/stat_notify_more"
                 android:visibility="gone"
                 />
-
+            <com.android.systemui.statusbar.StatusBarIconView android:id="@+id/modeIcon"
+                android:layout_width="@dimen/status_bar_icon_size"
+                android:layout_height="match_parent"
+                android:visibility="gone"
+                />
             <com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 1693e01..56c1f4e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -58,6 +58,12 @@
             android:layout_height="@dimen/notification_panel_header_height"
             />
 
+        <com.android.systemui.statusbar.phone.ZenModeView
+            android:id="@+id/zenmode"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+
         <TextView
             android:id="@+id/emergency_calls_only"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 9aa7cfd..25c516b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -15,7 +15,7 @@
 ** limitations under the License.
 -->
 
-<LinearLayout
+<com.android.systemui.statusbar.phone.PanelHeaderView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/header"
@@ -106,4 +106,4 @@
             android:contentDescription="@string/accessibility_notifications_button"
             />
     </FrameLayout>
-</LinearLayout>
+</com.android.systemui.statusbar.phone.PanelHeaderView>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e6b2b8b..65cd2319 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -79,6 +79,9 @@
     <!-- Height of a large notification in the status bar -->
     <dimen name="notification_max_height">256dp</dimen>
 
+    <!-- Height of a medium notification in the status bar -->
+    <dimen name="notification_mid_height">128dp</dimen>
+
     <!-- Height of a small notification in the status bar plus glow, padding, etc -->
     <dimen name="notification_row_min_height">70dp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 7ff52de..fb11743 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -96,7 +96,7 @@
     protected static final boolean ENABLE_HEADS_UP = true;
     // scores above this threshold should be displayed in heads up mode.
     protected static final int INTERRUPTION_THRESHOLD = 11;
-    protected static final String SETTING_HEADS_UP = "heads_up_enabled";
+    protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
 
     // Should match the value in PhoneWindowManager
     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
@@ -104,6 +104,9 @@
     public static final int EXPANDED_LEAVE_ALONE = -10000;
     public static final int EXPANDED_FULL_OPEN = -10001;
 
+    private static final String EXTRA_INTERCEPT = "android.intercept";
+    private static final float INTERCEPTED_ALPHA = .2f;
+
     protected CommandQueue mCommandQueue;
     protected IStatusBarService mBarService;
     protected H mHandler = createHandler();
@@ -128,6 +131,7 @@
     protected int mLayoutDirection = -1; // invalid
     private Locale mLocale;
     protected boolean mUseHeadsUp = false;
+    protected boolean mHeadsUpTicker = false;
 
     protected IDreamManager mDreamManager;
     PowerManager mPowerManager;
@@ -155,6 +159,8 @@
 
     private RecentsComponent mRecents;
 
+    protected int mZenMode;
+
     public IStatusBarService getStatusBarService() {
         return mBarService;
     }
@@ -163,7 +169,7 @@
         return mDeviceProvisioned;
     }
 
-    private final ContentObserver mProvisioningObserver = new ContentObserver(mHandler) {
+    protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
         @Override
         public void onChange(boolean selfChange) {
             final boolean provisioned = 0 != Settings.Global.getInt(
@@ -172,6 +178,9 @@
                 mDeviceProvisioned = provisioned;
                 updateNotificationIcons();
             }
+            final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+            setZenMode(mode);
         }
     };
 
@@ -239,10 +248,13 @@
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 
-        mProvisioningObserver.onChange(false); // set up
+        mSettingsObserver.onChange(false); // set up
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
-                mProvisioningObserver);
+                mSettingsObserver);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
+                mSettingsObserver);
 
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
@@ -683,6 +695,13 @@
         StatusBarNotification sbn = entry.notification;
         RemoteViews contentView = sbn.getNotification().contentView;
         RemoteViews bigContentView = sbn.getNotification().bigContentView;
+
+        if (isHeadsUp) {
+            maxHeight =
+                    mContext.getResources().getDimensionPixelSize(R.dimen.notification_mid_height);
+            bigContentView = sbn.getNotification().headsUpContentView;
+        }
+
         if (contentView == null) {
             return false;
         }
@@ -980,6 +999,7 @@
         if (DEBUG) {
             Log.d(TAG, "addNotificationViews: added at " + pos);
         }
+        updateInterceptedState(entry);
         updateExpansionStates();
         updateNotificationIcons();
     }
@@ -1010,6 +1030,35 @@
         }
     }
 
+    protected void setZenMode(int mode) {
+        if (!isDeviceProvisioned()) return;
+        final boolean change = mZenMode != mode;
+        mZenMode = mode;
+        final int N = mNotificationData.size();
+        for (int i = 0; i < N; i++) {
+            final NotificationData.Entry entry = mNotificationData.get(i);
+            if (change && !shouldIntercept()) {
+                entry.notification.getNotification().extras.putBoolean(EXTRA_INTERCEPT, false);
+            }
+            updateInterceptedState(entry);
+        }
+        updateNotificationIcons();
+    }
+
+    private boolean shouldIntercept() {
+        return mZenMode == Settings.Global.ZEN_MODE_LIMITED
+                || mZenMode == Settings.Global.ZEN_MODE_FULL;
+    }
+
+    protected boolean shouldIntercept(Notification n) {
+        return shouldIntercept() && n.extras.getBoolean(EXTRA_INTERCEPT);
+    }
+
+    private void updateInterceptedState(NotificationData.Entry entry) {
+        final boolean intercepted = shouldIntercept(entry.notification.getNotification());
+        entry.row.findViewById(R.id.container).setAlpha(intercepted ? INTERCEPTED_ALPHA : 1);
+    }
+
     protected abstract void haltTicker();
     protected abstract void setAreThereNotifications();
     protected abstract void updateNotificationIcons();
@@ -1038,6 +1087,8 @@
         final RemoteViews contentView = notification.getNotification().contentView;
         final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView;
         final RemoteViews bigContentView = notification.getNotification().bigContentView;
+        final RemoteViews oldHeadsUpContentView = oldNotification.getNotification().headsUpContentView;
+        final RemoteViews headsUpContentView = notification.getNotification().headsUpContentView;
         final Notification oldPublicNotification = oldNotification.getNotification().publicVersion;
         final RemoteViews oldPublicContentView = oldPublicNotification != null
                 ? oldPublicNotification.contentView : null;
@@ -1077,6 +1128,13 @@
                     && oldBigContentView.getPackage() != null
                     && oldBigContentView.getPackage().equals(bigContentView.getPackage())
                     && oldBigContentView.getLayoutId() == bigContentView.getLayoutId());
+        boolean headsUpContentsUnchanged =
+                (oldHeadsUpContentView == null && headsUpContentView == null)
+                || ((oldHeadsUpContentView != null && headsUpContentView != null)
+                    && headsUpContentView.getPackage() != null
+                    && oldHeadsUpContentView.getPackage() != null
+                    && oldHeadsUpContentView.getPackage().equals(headsUpContentView.getPackage())
+                    && oldHeadsUpContentView.getLayoutId() == headsUpContentView.getLayoutId());
         boolean publicUnchanged  =
                 (oldPublicContentView == null && publicContentView == null)
                 || ((oldPublicContentView != null && publicContentView != null)
@@ -1095,7 +1153,7 @@
                 && !TextUtils.equals(notification.getNotification().tickerText,
                         oldEntry.notification.getNotification().tickerText);
         boolean isTopAnyway = isTopNotification(rowParent, oldEntry);
-        if (contentsUnchanged && bigContentsUnchanged && publicUnchanged
+        if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged && publicUnchanged
                 && (orderUnchanged || isTopAnyway)) {
             if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
             oldEntry.notification = notification;
@@ -1179,7 +1237,9 @@
     private void updateNotificationViews(NotificationData.Entry entry,
             StatusBarNotification notification, boolean isHeadsUp) {
         final RemoteViews contentView = notification.getNotification().contentView;
-        final RemoteViews bigContentView = notification.getNotification().bigContentView;
+        final RemoteViews bigContentView = isHeadsUp
+                ? notification.getNotification().headsUpContentView
+                : notification.getNotification().bigContentView;
         final Notification publicVersion = notification.getNotification().publicVersion;
         final RemoteViews publicContentView = publicVersion != null ? publicVersion.contentView
                 : null;
@@ -1202,6 +1262,7 @@
         } else {
             entry.content.setOnClickListener(null);
         }
+        updateInterceptedState(entry);
     }
 
     protected void notifyHeadsUpScreenOn(boolean screenOn) {
@@ -1219,11 +1280,12 @@
                 || notification.vibrate != null;
         boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD;
         boolean isFullscreen = notification.fullScreenIntent != null;
+        boolean hasTicker = mHeadsUpTicker && !TextUtils.isEmpty(notification.tickerText);
         boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP,
                 Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER;
 
         final KeyguardTouchDelegate keyguard = KeyguardTouchDelegate.getInstance(mContext);
-        boolean interrupt = (isFullscreen || (isHighPriority && isNoisy))
+        boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker)))
                 && isAllowed
                 && mPowerManager.isScreenOn()
                 && !keyguard.isShowingAndNotHidden()
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 6be6d4d..237b7f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -20,6 +20,7 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.view.MotionEvent;
@@ -56,6 +57,17 @@
         mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
         mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height);
         mHandleView = findViewById(R.id.handle);
+        PanelHeaderView header = (PanelHeaderView) findViewById(R.id.header);
+        ZenModeView zenModeView = (ZenModeView) findViewById(R.id.zenmode);
+        zenModeView.setAdapter(new ZenModeViewAdapter(mContext) {
+            @Override
+            public void configure() {
+                if (mStatusBar != null) {
+                    mStatusBar.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS);
+                }
+            }
+        });
+        header.setZenModeView(zenModeView);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java
new file mode 100644
index 0000000..a28324d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java
@@ -0,0 +1,70 @@
+/*
+ * 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 android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.widget.LinearLayout;
+
+public class PanelHeaderView extends LinearLayout {
+    private static final String TAG = "PanelHeaderView";
+    private static final boolean DEBUG = false;
+
+    private ZenModeView mZenModeView;
+
+    public PanelHeaderView(Context context) {
+        super(context);
+    }
+
+    public PanelHeaderView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void setZenModeView(ZenModeView zmv) {
+        mZenModeView = zmv;
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        final boolean rt = super.dispatchTouchEvent(ev);
+        if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev);
+        if (mZenModeView != null) {
+            mZenModeView.dispatchExternalTouchEvent(ev);
+        }
+        return rt;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        final boolean rt = super.onInterceptTouchEvent(ev);
+        if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev);
+        return rt;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        boolean rt = super.onTouchEvent(event);
+        if (DEBUG) logTouchEvent("onTouchEvent", rt, event);
+        return true;
+    }
+
+    private void logTouchEvent(String method, boolean rt, MotionEvent ev) {
+        Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + ev);
+    }
+}
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 2114991..6718de1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -189,6 +189,8 @@
     IconMerger mNotificationIcons;
     // [+>
     View mMoreIcon;
+    // mode indicator icon
+    ImageView mModeIcon;
 
     // expanded notifications
     NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -310,13 +312,17 @@
         @Override
         public void onChange(boolean selfChange) {
             boolean wasUsing = mUseHeadsUp;
-            mUseHeadsUp = ENABLE_HEADS_UP && 0 != Settings.Global.getInt(
-                    mContext.getContentResolver(), SETTING_HEADS_UP, 0);
+            mUseHeadsUp = ENABLE_HEADS_UP && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
+                    mContext.getContentResolver(), Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+                    Settings.Global.HEADS_UP_OFF);
+            mHeadsUpTicker = mUseHeadsUp && 0 != Settings.Global.getInt(
+                    mContext.getContentResolver(), SETTING_HEADS_UP_TICKER, 0);
             Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
             if (wasUsing != mUseHeadsUp) {
                 if (!mUseHeadsUp) {
                     Log.d(TAG, "dismissing any existing heads up notification on disable event");
-                    mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+                    setHeadsUpVisibility(false);
+                    mHeadsUpNotificationView.setNotification(null);
                     removeHeadsUpView();
                 } else {
                     addHeadsUpView();
@@ -341,6 +347,20 @@
         }};
 
     @Override
+    public void setZenMode(int mode) {
+        super.setZenMode(mode);
+        if (mModeIcon == null) return;
+        if (!isDeviceProvisioned()) return;
+        final boolean limited = mode == Settings.Global.ZEN_MODE_LIMITED;
+        final boolean full = mode == Settings.Global.ZEN_MODE_FULL;
+        mModeIcon.setVisibility(full || limited ? View.VISIBLE : View.GONE);
+        final int icon = limited ? R.drawable.stat_sys_zen_limited : R.drawable.stat_sys_zen_full;
+        if (full || limited) {
+            mModeIcon.setImageResource(icon);
+        }
+    }
+
+    @Override
     public void start() {
         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay();
@@ -352,11 +372,15 @@
 
         // Lastly, call to the icon policy to install/update all the icons.
         mIconPolicy = new PhoneStatusBarPolicy(mContext);
+        mSettingsObserver.onChange(false); // set up
 
         mHeadsUpObserver.onChange(true); // set up
         if (ENABLE_HEADS_UP) {
             mContext.getContentResolver().registerContentObserver(
-                    Settings.Global.getUriFor(SETTING_HEADS_UP), true,
+                    Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true,
+                    mHeadsUpObserver);
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
                     mHeadsUpObserver);
         }
     }
@@ -455,6 +479,7 @@
         mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
         mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
         mNotificationIcons.setOverflowIndicator(mMoreIcon);
+        mModeIcon = (ImageView)mStatusBarView.findViewById(R.id.modeIcon);
         mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
         mTickerView = mStatusBarView.findViewById(R.id.ticker);
 
@@ -855,7 +880,6 @@
                 PixelFormat.TRANSLUCENT);
         lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         lp.gravity = Gravity.TOP;
-        lp.y = getStatusBarHeight();
         lp.setTitle("Heads Up");
         lp.packageName = mContext.getPackageName();
         lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp;
@@ -909,41 +933,43 @@
         if (shadeEntry == null) {
             return;
         }
-        if (mUseHeadsUp && shouldInterrupt(notification)) {
-            if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
-            Entry interruptionCandidate = new Entry(key, notification, null);
-            ViewGroup holder = mHeadsUpNotificationView.getHolder();
-            if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
-                mInterruptingNotificationTime = System.currentTimeMillis();
-                mInterruptingNotificationEntry = interruptionCandidate;
-                shadeEntry.setInterruption();
+        if (!shouldIntercept(notification.getNotification())) {
+            if (mUseHeadsUp && shouldInterrupt(notification)) {
+                if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
+                Entry interruptionCandidate = new Entry(key, notification, null);
+                ViewGroup holder = mHeadsUpNotificationView.getHolder();
+                if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
+                    mInterruptingNotificationTime = System.currentTimeMillis();
+                    mInterruptingNotificationEntry = interruptionCandidate;
+                    shadeEntry.setInterruption();
 
-                // 1. Populate mHeadsUpNotificationView
-                mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
+                    // 1. Populate mHeadsUpNotificationView
+                    mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
 
-                // 2. Animate mHeadsUpNotificationView in
-                mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
+                    // 2. Animate mHeadsUpNotificationView in
+                    mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
 
-                // 3. Set alarm to age the notification off
-                resetHeadsUpDecayTimer();
-            }
-        } else if (notification.getNotification().fullScreenIntent != null) {
-            // Stop screensaver if the notification has a full-screen intent.
-            // (like an incoming phone call)
-            awakenDreams();
+                    // 3. Set alarm to age the notification off
+                    resetHeadsUpDecayTimer();
+                }
+            } else if (notification.getNotification().fullScreenIntent != null) {
+                // Stop screensaver if the notification has a full-screen intent.
+                // (like an incoming phone call)
+                awakenDreams();
 
-            // not immersive & a full-screen alert should be shown
-            if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
-            try {
-                notification.getNotification().fullScreenIntent.send();
-            } catch (PendingIntent.CanceledException e) {
-            }
-        } else {
-            // usual case: status bar visible & not immersive
+                // not immersive & a full-screen alert should be shown
+                if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
+                try {
+                    notification.getNotification().fullScreenIntent.send();
+                } catch (PendingIntent.CanceledException e) {
+                }
+            } else {
+                // usual case: status bar visible & not immersive
 
-            // show the ticker if there isn't already a heads up
-            if (mInterruptingNotificationEntry == null) {
-                tick(null, notification, true);
+                // show the ticker if there isn't already a heads up
+                if (mInterruptingNotificationEntry == null) {
+                    tick(null, notification, true);
+                }
             }
         }
         addNotificationViews(shadeEntry);
@@ -1096,6 +1122,9 @@
                 // in "public" mode (atop a secure keyguard), secret notifs are totally hidden
                 continue;
             }
+            if (shouldIntercept(ent.notification.getNotification())) {
+                continue;
+            }
             toShow.add(ent.icon);
         }
 
@@ -2183,6 +2212,9 @@
         pw.println(windowStateToString(mStatusBarWindowState));
         pw.print("  mStatusBarMode=");
         pw.println(BarTransitions.modeToString(mStatusBarMode));
+        pw.print("  mZenMode=");
+        pw.println(Settings.Global.zenModeToString(mZenMode));
+        pw.print("  mUseHeadsUp=" + mUseHeadsUp);
         dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
         if (mNavigationBarView != null) {
             pw.print("  mNavigationBarWindowState=");
@@ -2710,6 +2742,12 @@
                 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
     }
 
+    public void startSettingsActivity(String action) {
+        if (mQS != null) {
+            mQS.startSettingsActivity(action);
+        }
+    }
+
     private static class FastColorDrawable extends Drawable {
         private final int mColor;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index bcb818a..c1c8946 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -278,7 +278,7 @@
         mTilesSetUp = true;
     }
 
-    private void startSettingsActivity(String action) {
+    public void startSettingsActivity(String action) {
         Intent intent = new Intent(action);
         startSettingsActivity(intent);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
new file mode 100644
index 0000000..783e371
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
@@ -0,0 +1,739 @@
+/*
+ * 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 android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.PathShape;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.text.method.LinkMovementMethod;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.URLSpan;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.PopupWindow;
+import android.widget.RelativeLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition;
+
+public class ZenModeView extends RelativeLayout {
+    private static final String TAG = ZenModeView.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private static final Typeface CONDENSED =
+            Typeface.create("sans-serif-condensed", Typeface.NORMAL);
+    private static final int GRAY = 0xff999999; //TextAppearance.StatusBar.Expanded.Network
+    private static final int BACKGROUND = 0xff1d3741; //0x3333b5e5;
+    private static final long DURATION = new ValueAnimator().getDuration();
+    private static final long BOUNCE_DURATION = DURATION / 3;
+    private static final float BOUNCE_SCALE = 0.8f;
+    private static final float SETTINGS_ALPHA = 0.6f;
+
+    private static final String FULL_TEXT =
+            "You won't hear any calls, alarms or timers.";
+
+    private final Context mContext;
+    private final Paint mPathPaint;
+    private final TextView mHintText;
+    private final ModeSpinner mModeSpinner;
+    private final ImageView mCloseButton;
+    private final ImageView mSettingsButton;
+    private final Rect mLayoutRect = new Rect();
+    private final UntilPager mUntilPager;
+    private final AlarmWarning mAlarmWarning;
+
+    private float mDownY;
+    private int mDownBottom;
+    private boolean mPeekable = true;
+    private boolean mClosing;
+    private int mBottom;
+    private int mWidthSpec;
+    private Adapter mAdapter;
+
+    public ZenModeView(Context context) {
+        this(context, null);
+    }
+
+    public ZenModeView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        if (DEBUG) log("new %s()", getClass().getSimpleName());
+        mContext = context;
+
+        mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mPathPaint.setStyle(Paint.Style.STROKE);
+        mPathPaint.setColor(GRAY);
+        mPathPaint.setStrokeWidth(5);
+
+        final int iconSize = mContext.getResources()
+                .getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width);
+        final int topRowSize = iconSize * 2 / 3;
+
+        mCloseButton = new ImageView(mContext);
+        mCloseButton.setAlpha(0f);
+        mCloseButton.setImageDrawable(sd(closePath(topRowSize), topRowSize, mPathPaint));
+        addView(mCloseButton, new LayoutParams(topRowSize, topRowSize));
+        mCloseButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                bounce(v, null);
+                close();
+            }
+        });
+
+        mSettingsButton = new ImageView(mContext);
+        mSettingsButton.setAlpha(0f);
+        final int p = topRowSize / 7;
+        mSettingsButton.setPadding(p, p, p, p);
+        mSettingsButton.setImageResource(R.drawable.ic_notify_settings_normal);
+        LayoutParams lp = new LayoutParams(topRowSize, topRowSize);
+        lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+        addView(mSettingsButton, lp);
+        mSettingsButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mAdapter != null && mAdapter.getMode() == Adapter.MODE_LIMITED) {
+                    mAdapter.configure();
+                }
+                bounce(mSettingsButton, null);
+            }
+        });
+
+        mModeSpinner = new ModeSpinner(mContext);
+        mModeSpinner.setAlpha(0);
+        mModeSpinner.setEnabled(false);
+        mModeSpinner.setId(android.R.id.title);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
+        lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
+        addView(mModeSpinner, lp);
+
+
+        mUntilPager = new UntilPager(mContext, mPathPaint, iconSize);
+        mUntilPager.setId(android.R.id.tabhost);
+        mUntilPager.setAlpha(0);
+        lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+        lp.addRule(BELOW, mModeSpinner.getId());
+        addView(mUntilPager, lp);
+
+        mAlarmWarning = new AlarmWarning(mContext);
+        mAlarmWarning.setAlpha(0);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+        lp.addRule(CENTER_HORIZONTAL);
+        lp.addRule(BELOW, mUntilPager.getId());
+        addView(mAlarmWarning, lp);
+
+        mHintText = new TextView(mContext);
+        mHintText.setTypeface(CONDENSED);
+        mHintText.setText("Swipe down for Limited Interruptions");
+        mHintText.setGravity(Gravity.CENTER);
+        mHintText.setTextColor(GRAY);
+        addView(mHintText, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+    }
+
+    private boolean isApplicable() {
+        return mAdapter != null && mAdapter.isApplicable();
+    }
+
+    private void close() {
+        mClosing = true;
+        final int startBottom = mBottom;
+        final int max = mPeekable ? getExpandedBottom() : startBottom;
+        mHintText.animate().alpha(1).setUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                final float f = animation.getAnimatedFraction();
+                final int hintBottom = mHintText.getBottom();
+                setPeeked(hintBottom + (int)((1-f) * (startBottom - hintBottom)), max);
+                if (f == 1) {
+                    mPeekable = true;
+                    mClosing = false;
+                    mModeSpinner.updateState();
+                    if (mAdapter != null) {
+                        mAdapter.cancel();
+                    }
+                }
+            }
+        }).start();
+        mUntilPager.animate().alpha(0).start();
+        mAlarmWarning.animate().alpha(0).start();
+    }
+
+    public void setAdapter(Adapter adapter) {
+        mAdapter = adapter;
+        mAdapter.setCallbacks(new Adapter.Callbacks() {
+            @Override
+            public void onChanged() {
+                post(new Runnable() {
+                    @Override
+                    public void run() {
+                        updateState(true);
+                    }
+                });
+            }
+        });
+        updateState(false);
+    }
+
+    private void updateState(boolean animate) {
+        final boolean applicable = isApplicable();
+        setVisibility(applicable ? VISIBLE : GONE);
+        if (!applicable) {
+            return;
+        }
+        if (mAdapter != null && mAdapter.getMode() == Adapter.MODE_OFF && !mPeekable) {
+            close();
+        } else {
+            mModeSpinner.updateState();
+            mUntilPager.updateState();
+            mAlarmWarning.updateState(animate);
+            final float settingsAlpha = getSettingsButtonAlpha();
+            if (settingsAlpha != mSettingsButton.getAlpha()) {
+                if (animate) {
+                    mSettingsButton.animate().alpha(settingsAlpha).start();
+                } else {
+                    mSettingsButton.setAlpha(settingsAlpha);
+                }
+            }
+            if (mPeekable && mAdapter != null && mAdapter.getMode() != Adapter.MODE_OFF) {
+                if (DEBUG) log("panic expand!");
+                mPeekable = false;
+                mModeSpinner.setEnabled(true);
+                mBottom = getExpandedBottom();
+                setExpanded(1);
+            }
+        }
+    }
+
+    private float getSettingsButtonAlpha() {
+        final boolean full = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL;
+        final boolean collapsed = mHintText.getAlpha() == 1;
+        return full || collapsed ? 0 : SETTINGS_ALPHA;
+    }
+
+    private static Path closePath(int size) {
+        final int pad = size / 4;
+        final Path p = new Path();
+        p.moveTo(pad, pad);
+        p.lineTo(size - pad, size - pad);
+        p.moveTo(size - pad, pad);
+        p.lineTo(pad, size - pad);
+        return p;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (DEBUG) log("onMeasure %s %s",
+                MeasureSpec.toString(widthMeasureSpec), MeasureSpec.toString(heightMeasureSpec));
+        if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY) {
+            throw new UnsupportedOperationException("Width must be exact");
+        }
+        if (widthMeasureSpec != mWidthSpec) {
+            if (DEBUG) log("  super.onMeasure");
+            final int hms = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            super.onMeasure(widthMeasureSpec, hms);
+            mBottom = mPeekable ? mHintText.getMeasuredHeight() : getExpandedBottom();
+            mWidthSpec = widthMeasureSpec;
+        }
+        if (DEBUG) log("mBottom (OM) = " + mBottom);
+        setMeasuredDimension(getMeasuredWidth(), mBottom);
+        if (DEBUG) log("  mw=%s mh=%s",
+                toString(getMeasuredWidthAndState()), toString(getMeasuredHeightAndState()));
+    }
+
+    private static String toString(int sizeAndState) {
+        final int size = sizeAndState & MEASURED_SIZE_MASK;
+        final boolean tooSmall = (sizeAndState & MEASURED_STATE_TOO_SMALL) != 0;
+        return size + (tooSmall ? "TOO SMALL" : "");
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        mLayoutRect.set(left, top, right, bottom);
+        if (DEBUG) log("onLayout %s %s %dx%d", changed,
+                mLayoutRect.toShortString(), mLayoutRect.width(), mLayoutRect.height());
+        super.onLayout(changed, left, top, right, bottom);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        final boolean rt = super.dispatchTouchEvent(ev);
+        if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev);
+        return rt;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        final boolean rt = super.onInterceptTouchEvent(ev);
+        if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev);
+        if (isApplicable()
+                && ev.getAction() == MotionEvent.ACTION_DOWN
+                && ev.getY() > mCloseButton.getBottom()
+                && mPeekable) {
+            return true;
+        }
+        return rt;
+    }
+
+    private static void logTouchEvent(String method, boolean rt, MotionEvent event) {
+        final String action = MotionEvent.actionToString(event.getAction());
+        Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + action);
+    }
+
+    private int getExpandedBottom() {
+        int b = mModeSpinner.getMeasuredHeight() + mUntilPager.getMeasuredHeight();
+        if (mAlarmWarning.getAlpha() == 1) b += mAlarmWarning.getMeasuredHeight();
+        return b;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        boolean rt = super.onTouchEvent(event);
+        if (DEBUG) logTouchEvent("onTouchEvent", rt, event);
+        if (!isApplicable() || !mPeekable) {
+            return rt;
+        }
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            mDownY = event.getY();
+            if (DEBUG) log("  mDownY=" + mDownY);
+            mDownBottom = mBottom;
+            return true;
+        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+            final float dy = event.getY() - mDownY;
+            setPeeked(mDownBottom + (int)dy, getExpandedBottom());
+        } else if (event.getAction() == MotionEvent.ACTION_UP
+                || event.getAction() == MotionEvent.ACTION_CANCEL) {
+            final float dy = event.getY() - mDownY;
+            setPeeked(mDownBottom + (int)dy, getExpandedBottom());
+            if (mPeekable) {
+                close();
+            }
+        }
+        return rt;
+    }
+
+    private void setPeeked(int peeked, int max) {
+        if (DEBUG) log("setPeeked=" + peeked);
+        final int min = mHintText.getBottom();
+        peeked = Math.max(min, Math.min(peeked, max));
+        if (mBottom == peeked) {
+            return;
+        }
+        if (peeked == max) {
+            mPeekable = false;
+            mModeSpinner.setEnabled(true);
+            if (mAdapter != null) {
+                mAdapter.setMode(Adapter.MODE_LIMITED);
+            }
+        }
+        if (peeked == min) {
+            mPeekable = true;
+            mModeSpinner.setEnabled(false);
+        }
+        if (DEBUG) log("  mBottom=" + peeked);
+        mBottom = peeked;
+        final float f = (peeked - min) / (float)(max - min);
+        setExpanded(f);
+        requestLayout();
+    }
+
+    private void setExpanded(float f) {
+        if (DEBUG) log("setExpanded " + f);
+        final int a = (int)(Color.alpha(BACKGROUND) * f);
+        setBackgroundColor(Color.argb(a,
+                Color.red(BACKGROUND), Color.green(BACKGROUND), Color.blue(BACKGROUND)));
+        mHintText.setAlpha(1 - f);
+        mCloseButton.setAlpha(f);
+        mModeSpinner.setAlpha(f);
+        mUntilPager.setAlpha(f);
+        mSettingsButton.setAlpha(f * getSettingsButtonAlpha());
+    }
+
+    private static void log(String msg, Object... args) {
+        Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
+    }
+
+    private static ShapeDrawable sd(Path p, int size, Paint pt) {
+        final ShapeDrawable sd = new ShapeDrawable(new PathShape(p, size, size));
+        sd.getPaint().set(pt);
+        sd.setIntrinsicHeight(size);
+        sd.setIntrinsicWidth(size);
+        return sd;
+    }
+
+    public void dispatchExternalTouchEvent(MotionEvent ev) {
+        if (isApplicable()) {
+            onTouchEvent(ev);
+        }
+    }
+
+    private static void bounce(final View v, final Runnable midBounce) {
+        v.animate().scaleX(BOUNCE_SCALE).scaleY(BOUNCE_SCALE).setDuration(DURATION / 3)
+            .setListener(new AnimatorListenerAdapter() {
+                private boolean mFired;
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (!mFired) {
+                        mFired = true;
+                        if (midBounce != null) {
+                            midBounce.run();
+                        }
+                        v.animate().scaleX(1).scaleY(1).setListener(null).start();
+                    }
+                }
+            }).start();
+    }
+
+    private final class UntilPager extends RelativeLayout {
+        private final ImageView mPrev;
+        private final ImageView mNext;
+        private final TextView mText1;
+        private final TextView mText2;
+
+        private TextView mText;
+
+        public UntilPager(Context context, Paint pathPaint, int iconSize) {
+            super(context);
+            mText1 = new TextView(mContext);
+            mText1.setTypeface(CONDENSED);
+            mText1.setTextColor(GRAY);
+            mText1.setGravity(Gravity.CENTER);
+            LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, iconSize);
+            addView(mText1, lp);
+            mText = mText1;
+
+            mText2 = new TextView(mContext);
+            mText2.setTypeface(CONDENSED);
+            mText2.setTextColor(GRAY);
+            mText2.setAlpha(0);
+            mText2.setGravity(Gravity.CENTER);
+            addView(mText2, lp);
+
+            lp = new LayoutParams(iconSize, iconSize);
+            final View v = new View(mContext);
+            v.setBackgroundColor(BACKGROUND);
+            addView(v, lp);
+            mPrev = new ImageView(mContext);
+            mPrev.setId(android.R.id.button1);
+            mPrev.setImageDrawable(sd(prevPath(iconSize), iconSize, pathPaint));
+            addView(mPrev, lp);
+            mPrev.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    onNav(v, -1);
+                }
+            });
+
+            lp = new LayoutParams(iconSize, iconSize);
+            lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+            final View v2 = new View(mContext);
+            v2.setBackgroundColor(BACKGROUND);
+            addView(v2, lp);
+            mNext = new ImageView(mContext);
+            mNext.setId(android.R.id.button2);
+            mNext.setImageDrawable(sd(nextPath(iconSize), iconSize, pathPaint));
+            addView(mNext, lp);
+            mNext.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    onNav(v, 1);
+                }
+            });
+
+            updateState();
+        }
+
+        private void onNav(View v, int d) {
+            bounce(v, null);
+            if (mAdapter == null) {
+                return;
+            }
+            if (mAdapter.getExitConditionCount() == 1) {
+                horBounce(d);
+                return;
+            }
+            final int w = getWidth();
+            final float s = Math.signum(d);
+            final TextView current = mText;
+            final TextView other = mText == mText1 ? mText2 : mText1;
+            final ExitCondition ec = mAdapter.getExitCondition(d);
+            setText(other, ec);
+            other.setTranslationX(-s * w);
+            other.animate().translationX(0).alpha(1).setDuration(DURATION).start();
+            current.animate().translationX(s * w).alpha(0).setDuration(DURATION).start();
+            mText = other;
+            mAdapter.select(ec);
+        }
+
+        private void horBounce(int d) {
+            final int w = getWidth();
+            mText.animate()
+                    .setDuration(BOUNCE_DURATION)
+                    .translationX(Math.signum(d) * w / 20)
+                    .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            mText.animate().translationX(0).setListener(null).start();
+                        }
+                    }).start();
+        }
+
+        private void setText(final TextView textView, final ExitCondition ec) {
+            SpannableStringBuilder ss = new SpannableStringBuilder(ec.line1 + "\n" + ec.line2);
+            ss.setSpan(new RelativeSizeSpan(1.5f), (ec.line1 + "\n").length(), ss.length(),
+                    Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+            if (ec.action != null) {
+                ss.setSpan(new CustomLinkSpan() {
+                    @Override
+                    public void onClick() {
+                        // TODO wire up links
+                        Toast.makeText(mContext, ec.action, Toast.LENGTH_SHORT).show();
+                    }
+                }, (ec.line1 + "\n").length(), ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+                textView.setMovementMethod(LinkMovementMethod.getInstance());
+            } else {
+                textView.setMovementMethod(null);
+            }
+            textView.setText(ss);
+        }
+
+        private void updateState() {
+            if (mAdapter == null) {
+                return;
+            }
+            setText(mText, mAdapter.getExitCondition(0));
+        }
+
+        private Path prevPath(int size) {
+            final int hp = size / 3;
+            final int vp = size / 4;
+            final Path p = new Path();
+            p.moveTo(size - hp, vp);
+            p.lineTo(hp, size / 2);
+            p.lineTo(size - hp, size - vp);
+            return p;
+        }
+
+        private Path nextPath(int size) {
+            final int hp = size / 3;
+            final int vp = size / 4;
+            Path p = new Path();
+            p.moveTo(hp, vp);
+            p.lineTo(size - hp, size / 2);
+            p.lineTo(hp, size - vp);
+            return p;
+        }
+    }
+
+    private abstract static class CustomLinkSpan extends URLSpan {
+        abstract public void onClick();
+
+        public CustomLinkSpan() {
+            super("#");
+        }
+
+        @Override
+        public void updateDrawState(TextPaint ds) {
+            super.updateDrawState(ds);
+            ds.setUnderlineText(false);
+            ds.bgColor = BACKGROUND;
+        }
+
+        @Override
+        public void onClick(View widget) {
+            onClick();
+        }
+    }
+
+    public interface Adapter {
+        public static final int MODE_OFF = 0;
+        public static final int MODE_LIMITED = 1;
+        public static final int MODE_FULL = 2;
+
+        boolean isApplicable();
+        void configure();
+        int getMode();
+        void setMode(int mode);
+        void select(ExitCondition ec);
+        void cancel();
+        void setCallbacks(Callbacks callbacks);
+        ExitCondition getExitCondition(int d);
+        int getExitConditionCount();
+
+        public static class ExitCondition {
+            public String summary;
+            public String line1;
+            public String line2;
+            public String action;
+        }
+
+        public interface Callbacks {
+            void onChanged();
+        }
+    }
+
+    private final class ModeSpinner extends Spinner {
+        public ModeSpinner(final Context context) {
+            super(context);
+            setBackgroundResource(R.drawable.spinner_default_holo_dark_am_no_underline);
+            final ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(mContext, 0) {
+                @Override
+                public View getView(int position, View convertView,  ViewGroup parent) {
+                    if (DEBUG) log("getView %s parent=%s", position, parent);
+                    return getDropDownView(position, convertView, parent);
+                }
+
+                @Override
+                public View getDropDownView(int position, View convertView, ViewGroup parent) {
+                    if (DEBUG) log("getDropDownView %s cv=%s parent=%s",
+                            position, convertView, parent);
+                    final TextView tv = convertView != null ? (TextView) convertView
+                            : new TextView(context);
+                    final int mode = getItem(position);
+                    tv.setText(modeToString(mode));
+                    if (convertView == null) {
+                        if (DEBUG) log(" setting up view");
+                        tv.setTextColor(GRAY);
+                        tv.setTypeface(CONDENSED);
+                        tv.setAllCaps(true);
+                        tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.5f);
+                        final int p = (int) tv.getTextSize() / 2;
+                        if (parent instanceof ListView) {
+                            tv.setPadding(p, p, p, p);
+                        } else {
+                            tv.setGravity(Gravity.CENTER_HORIZONTAL);
+                            tv.setPadding(p, 0, p, 0);
+                        }
+                    }
+                    tv.setOnTouchListener(new OnTouchListener(){
+                        @Override
+                        public boolean onTouch(View v, MotionEvent event) {
+                            if (DEBUG) log("onTouch %s %s", tv.getText(),
+                                    MotionEvent.actionToString(event.getAction()));
+                            if (mAdapter != null) {
+                                mAdapter.setMode(mode);
+                            }
+                            return false;
+                        }
+
+                    });
+                    return tv;
+                }
+            };
+            adapter.add(Adapter.MODE_LIMITED);
+            adapter.add(Adapter.MODE_FULL);
+            setAdapter(adapter);
+        }
+
+        public void updateState() {
+            int mode = mAdapter != null ? mAdapter.getMode() : Adapter.MODE_LIMITED;
+            if (mode == Adapter.MODE_OFF) {
+                mode = Adapter.MODE_LIMITED;
+            }
+            if (DEBUG) log("setSelectedMode " + mode);
+            for (int i = 0; i < getAdapter().getCount(); i++) {
+                if (getAdapter().getItem(i).equals(mode)) {
+                    if (DEBUG) log("  setting selection = " + i);
+                    setSelection(i, true);
+                    return;
+                }
+            }
+        }
+
+        private String modeToString(int mode) {
+            if (mode == Adapter.MODE_LIMITED) return "Limited interruptions";
+            if (mode == Adapter.MODE_FULL) return "Zero interruptions";
+            throw new UnsupportedOperationException("Unsupported mode: " + mode);
+        }
+    }
+
+    private final class AlarmWarning extends LinearLayout {
+        public AlarmWarning(Context context) {
+            super(context);
+            setOrientation(HORIZONTAL);
+
+            final TextView tv = new TextView(mContext);
+            tv.setTextColor(GRAY);
+            tv.setGravity(Gravity.TOP);
+            tv.setTypeface(CONDENSED);
+            tv.setText(FULL_TEXT);
+            addView(tv);
+
+            final ImageView icon = new ImageView(mContext);
+            icon.setAlpha(.75f);
+            int size = (int)tv.getTextSize();
+            icon.setImageResource(android.R.drawable.ic_dialog_alert);
+            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(size, size);
+            final int p = size / 4;
+            lp.bottomMargin = lp.topMargin = lp.rightMargin = lp.leftMargin = p;
+            addView(icon, 0, lp);
+            setPadding(p, 0, p, p);
+        }
+
+        public void updateState(boolean animate) {
+            final boolean visible = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL;
+            final float alpha = visible ? 1 : 0;
+            if (alpha == getAlpha()) {
+                return;
+            }
+            if (animate) {
+                final boolean in = alpha == 1;
+                animate().alpha(alpha).setUpdateListener(new AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        if (mPeekable || mClosing) {
+                            return;
+                        }
+                        float f = animation.getAnimatedFraction();
+                        if (!in) {
+                            f = 1 - f;
+                        }
+                        ZenModeView.this.mBottom = mUntilPager.getBottom()
+                                + (int)(mAlarmWarning.getMeasuredHeight() * f);
+                        if (DEBUG) log("mBottom (AW) = " + mBottom);
+                        requestLayout();
+                    }
+                }).start();
+            } else {
+                setAlpha(alpha);
+                requestLayout();
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
new file mode 100644
index 0000000..39c4faa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
@@ -0,0 +1,173 @@
+/*
+ * 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 android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+
+public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
+    private static final String TAG = "ZenModeViewAdapter";
+
+    private final Context mContext;
+    private final ContentResolver mResolver;
+    private final Handler mHandler = new Handler();
+    private final SettingsObserver mObserver;
+    private final List<ExitCondition> mExits = Arrays.asList(
+            newExit("Until you delete this", "Until", "You delete this"));
+
+    private Callbacks mCallbacks;
+    private int mExitIndex;
+    private boolean mDeviceProvisioned;
+    private int mMode;
+
+    public ZenModeViewAdapter(Context context) {
+        mContext = context;
+        mResolver = mContext.getContentResolver();
+        mObserver = new SettingsObserver(mHandler);
+        mObserver.init();
+    }
+
+    @Override
+    public boolean isApplicable() {
+        return mDeviceProvisioned;
+    }
+
+    @Override
+    public int getMode() {
+        return mMode;
+    }
+
+    @Override
+    public void setMode(int mode) {
+        final int v = mode == MODE_LIMITED ? Settings.Global.ZEN_MODE_LIMITED
+                    : mode == MODE_FULL ? Settings.Global.ZEN_MODE_FULL
+                    : Settings.Global.ZEN_MODE_OFF;
+        AsyncTask.execute(new Runnable() {
+            @Override
+            public void run() {
+                Settings.Global.putInt(mContext.getContentResolver(),
+                        Settings.Global.ZEN_MODE, v);
+            }
+        });
+    }
+
+    @Override
+    public void cancel() {
+        if (mExitIndex != 0) {
+            mExitIndex = 0;
+            mHandler.post(mChange);
+        }
+        setMode(MODE_OFF);
+    }
+
+    @Override
+    public void setCallbacks(final Callbacks callbacks) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mCallbacks = callbacks;
+            }
+        });
+    }
+
+    @Override
+    public ExitCondition getExitCondition(int d) {
+        final int n = mExits.size();
+        final int i = (n + (mExitIndex + (int)Math.signum(d))) % n;
+        return mExits.get(i);
+    }
+
+    @Override
+    public int getExitConditionCount() {
+        return mExits.size();
+    }
+
+    @Override
+    public void select(ExitCondition ec) {
+        final int i = mExits.indexOf(ec);
+        if (i == -1 || i == mExitIndex) {
+            return;
+        }
+        mExitIndex = i;
+        mHandler.post(mChange);
+    }
+
+    private static ExitCondition newExit(String summary, String line1, String line2) {
+        final ExitCondition rt = new ExitCondition();
+        rt.summary = summary;
+        rt.line1 = line1;
+        rt.line2 = line2;
+        return rt;
+    }
+
+    private final Runnable mChange = new Runnable() {
+        public void run() {
+            if (mCallbacks == null) {
+                return;
+            }
+            try {
+                mCallbacks.onChanged();
+            } catch (Throwable t) {
+                Log.w(TAG, "Error dispatching onChanged to " + mCallbacks, t);
+            }
+        }
+    };
+
+    private final class SettingsObserver extends ContentObserver {
+        public SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void init() {
+            loadSettings();
+            mResolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
+                    false, this);
+            mResolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
+                    false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            loadSettings();
+            mChange.run();  // already on handler
+        }
+
+        private void loadSettings() {
+            mDeviceProvisioned = Settings.Global.getInt(mResolver,
+                    Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+            mMode = getMode();
+        }
+
+        private int getMode() {
+            final int v = Settings.Global.getInt(mResolver,
+                    Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+            if (v == Settings.Global.ZEN_MODE_LIMITED) return MODE_LIMITED;
+            if (v == Settings.Global.ZEN_MODE_FULL) return MODE_FULL;
+            return MODE_OFF;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 491c35e..79932a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -28,6 +28,7 @@
 import android.widget.FrameLayout;
 
 import com.android.systemui.ExpandHelper;
+import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -42,13 +43,13 @@
 
     private final int mTouchSensitivityDelay;
     private SwipeHelper mSwipeHelper;
+    private EdgeSwipeHelper mEdgeSwipeHelper;
 
     private BaseStatusBar mBar;
     private ExpandHelper mExpandHelper;
-    private long mStartTouchTime;
 
+    private long mStartTouchTime;
     private ViewGroup mContentHolder;
-    private ViewGroup mContentSlider;
 
     private NotificationData.Entry mHeadsUp;
 
@@ -72,19 +73,24 @@
 
     public boolean setNotification(NotificationData.Entry headsUp) {
         mHeadsUp = headsUp;
-        mHeadsUp.row.setExpanded(false);
-        mHeadsUp.row.setShowingPublic(false);
-        if (mContentHolder == null) {
-            // too soon!
-            return false;
+        if (mContentHolder != null) {
+            mContentHolder.removeAllViews();
         }
-        mContentHolder.setX(0);
-        mContentHolder.setVisibility(View.VISIBLE);
-        mContentHolder.setAlpha(1f);
-        mContentHolder.removeAllViews();
-        mContentHolder.addView(mHeadsUp.row);
-        mSwipeHelper.snapChild(mContentSlider, 1f);
-        mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay;
+
+        if (mHeadsUp != null) {
+            mHeadsUp.row.setExpanded(true);
+            mHeadsUp.row.setShowingPublic(false);
+            if (mContentHolder == null) {
+                // too soon!
+                return false;
+            }
+            mContentHolder.setX(0);
+            mContentHolder.setVisibility(View.VISIBLE);
+            mContentHolder.setAlpha(1f);
+            mContentHolder.addView(mHeadsUp.row);
+            mSwipeHelper.snapChild(mContentHolder, 1f);
+            mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay;
+        }
         return true;
     }
 
@@ -94,10 +100,11 @@
 
     public void setMargin(int notificationPanelMarginPx) {
         if (SPEW) Log.v(TAG, "setMargin() " + notificationPanelMarginPx);
-        if (mContentSlider != null) {
-            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentSlider.getLayoutParams();
+        if (mContentHolder != null &&
+                mContentHolder.getLayoutParams() instanceof FrameLayout.LayoutParams) {
+            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentHolder.getLayoutParams();
             lp.setMarginStart(notificationPanelMarginPx);
-            mContentSlider.setLayoutParams(lp);
+            mContentHolder.setLayoutParams(lp);
         }
     }
 
@@ -122,15 +129,17 @@
     @Override
     public void onAttachedToWindow() {
         float densityScale = getResources().getDisplayMetrics().density;
-        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
+        final ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
+        float pagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop();
+        float touchSlop = viewConfiguration.getScaledTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
+        mEdgeSwipeHelper = new EdgeSwipeHelper(touchSlop);
 
         int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
         int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
         mExpandHelper = new ExpandHelper(getContext(), this, minHeight, maxHeight);
 
         mContentHolder = (ViewGroup) findViewById(R.id.content_holder);
-        mContentSlider = (ViewGroup) findViewById(R.id.content_slider);
 
         if (mHeadsUp != null) {
             // whoops, we're on already!
@@ -144,7 +153,8 @@
         if (System.currentTimeMillis() < mStartTouchTime) {
             return true;
         }
-        return mSwipeHelper.onInterceptTouchEvent(ev)
+        return mEdgeSwipeHelper.onInterceptTouchEvent(ev)
+                || mSwipeHelper.onInterceptTouchEvent(ev)
                 || mExpandHelper.onInterceptTouchEvent(ev)
                 || super.onInterceptTouchEvent(ev);
     }
@@ -157,7 +167,8 @@
             return false;
         }
         mBar.resetHeadsUpDecayTimer();
-        return mSwipeHelper.onTouchEvent(ev)
+        return mEdgeSwipeHelper.onTouchEvent(ev)
+                || mSwipeHelper.onTouchEvent(ev)
                 || mExpandHelper.onTouchEvent(ev)
                 || super.onTouchEvent(ev);
     }
@@ -226,11 +237,65 @@
 
     @Override
     public View getChildAtPosition(MotionEvent ev) {
-        return mContentSlider;
+        return mContentHolder;
     }
 
     @Override
     public View getChildContentView(View v) {
-        return mContentSlider;
+        return mContentHolder;
+    }
+
+    private class EdgeSwipeHelper implements Gefingerpoken {
+        private static final boolean DEBUG_EDGE_SWIPE = false;
+        private final float mTouchSlop;
+        private boolean mConsuming;
+        private float mFirstY;
+        private float mFirstX;
+
+        public EdgeSwipeHelper(float touchSlop) {
+            mTouchSlop = touchSlop;
+        }
+
+        @Override
+        public boolean onInterceptTouchEvent(MotionEvent ev) {
+            switch (ev.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action down " + ev.getY());
+                    mFirstX = ev.getX();
+                    mFirstY = ev.getY();
+                    mConsuming = false;
+                    break;
+
+                case MotionEvent.ACTION_MOVE:
+                    if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action move " + ev.getY());
+                    final float dY = ev.getY() - mFirstY;
+                    final float daX = Math.abs(ev.getX() - mFirstX);
+                    final float daY = Math.abs(dY);
+                    if (!mConsuming && (4f * daX) < daY && daY > mTouchSlop) {
+                        if (dY > 0) {
+                            if (DEBUG_EDGE_SWIPE) Log.d(TAG, "found an open");
+                            mBar.animateExpandNotificationsPanel();
+                        }
+                        if (dY < 0) {
+                            if (DEBUG_EDGE_SWIPE) Log.d(TAG, "found a close");
+                            mBar.onHeadsUpDismissed();
+                        }
+                        mConsuming = true;
+                    }
+                    break;
+
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action done" );
+                    mConsuming = false;
+                    break;
+            }
+            return mConsuming;
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent ev) {
+            return mConsuming;
+        }
     }
 }
\ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index c73d90a..02a2680 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -29,6 +29,8 @@
 import android.transition.Transition;
 import android.transition.TransitionInflater;
 import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.util.ArrayMap;
 import android.view.ViewConfiguration;
 
 import com.android.internal.R;
@@ -105,6 +107,9 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Android-specific Window.
@@ -120,6 +125,13 @@
     private static final long MAX_TRANSITION_START_WAIT = 500;
     private static final long MAX_TRANSITION_FINISH_WAIT = 1000;
 
+    private static final String KEY_SCREEN_X = "shared_element:screenX";
+    private static final String KEY_SCREEN_Y = "shared_element:screenY";
+    private static final String KEY_TRANSLATION_Z = "shared_element:translationZ";
+    private static final String KEY_WIDTH = "shared_element:width";
+    private static final String KEY_HEIGHT = "shared_element:height";
+    private static final String KEY_NAME = "shared_element:name";
+
     /**
      * Simple callback used by the context menu and its submenus. The options
      * menu submenus do not use this (their behavior is more complex).
@@ -239,7 +251,8 @@
 
     private ActivityOptions mActivityOptions;
     private SceneTransitionListener mSceneTransitionListener;
-    private boolean mFadeEarly = true;
+    private boolean mTriggerEarly = true;
+    private Map<String, String> mSharedElementsMap;
 
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -2562,6 +2575,11 @@
             return super.fitSystemWindows(insets);
         }
 
+        @Override
+        public boolean isTransitionGroup() {
+            return false;
+        }
+
         private void updateStatusGuard(Rect insets) {
             boolean showStatusGuard = false;
             // Show the status guard when the non-overlay contextual action bar is showing
@@ -3988,78 +4006,214 @@
     }
 
     @Override
-    public void setEarlyBackgroundTransition(boolean fadeEarly) {
-        mFadeEarly = fadeEarly;
+    public void setTriggerEarlyEnterTransition(boolean triggerEarly) {
+        mTriggerEarly = triggerEarly;
     }
 
     @Override
-    public void startExitTransition(ActivityOptions activityOptions) {
-        Transition transition = mTransitionManager.getNamedTransition(getContentScene(), "null");
-        if (transition == null) {
-            transition = TransitionManager.getDefaultTransition().clone();
+    public void mapTransitionTargets(Map<String, String> sharedElementNames) {
+        mSharedElementsMap = sharedElementNames;
+    }
+
+    @Override
+    public Bundle startExitTransition(ActivityOptions activityOptions) {
+        if (mContentScene == null) {
+            return null;
         }
-        activityOptions.setExitTransition(transition, new ActivityOptions.SharedElementSource() {
+        Transition transition = mTransitionManager.getExitTransition(mContentScene);
+        if (transition == null) {
+            return null;
+        }
+
+        ArrayMap<String, View> sharedElements = findSharedElements(activityOptions);
+
+        // Find exiting Views and shared elements
+        final ArrayList<View> transitioningViews = new ArrayList<View>();
+        mDecor.captureTransitioningViews(transitioningViews);
+        transitioningViews.removeAll(sharedElements.values());
+
+        Transition exitTransition = cloneAndSetTransitionTargets(transition,
+                transitioningViews, true);
+        Transition sharedElementTransition = cloneAndSetTransitionTargets(transition,
+                transitioningViews, false);
+
+        // transitionSet is the total exit transition, including hero animation.
+        TransitionSet transitionSet = new TransitionSet();
+        transitionSet.addTransition(exitTransition);
+        transitionSet.addTransition(sharedElementTransition);
+
+        updateExitActivityOptions(activityOptions, sharedElements,
+                sharedElementTransition, exitTransition);
+
+        // Start exiting the Views that need to exit
+        TransitionManager.beginDelayedTransition(mDecor, transitionSet);
+        setViewVisibility(transitioningViews, View.INVISIBLE);
+
+        return activityOptions.toBundle();
+    }
+
+    private ArrayMap<String, View> findSharedElements(ActivityOptions activityOptions) {
+        ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
+        mDecor.findSharedElements(sharedElements);
+        ArrayList<String> localNames = activityOptions.getLocalElementNames();
+        sharedElements.keySet().retainAll(localNames);
+
+        ArrayList<String> targetNames = activityOptions.getSharedElementNames();
+        for (int i = 0; i < localNames.size(); i++) {
+            String localName = localNames.get(i);
+            View sharedElement = sharedElements.remove(localName);
+            String targetName = targetNames.get(i);
+            sharedElements.put(targetName, sharedElement);
+        }
+        return sharedElements;
+    }
+
+    private void updateExitActivityOptions(ActivityOptions activityOptions,
+            final Map<String, View> sharedElements, Transition sharedElementTransition,
+            Transition exitTransition) {
+
+        // Schedule capturing of the shared element state
+        final Bundle sharedElementArgs = new Bundle();
+        captureTerminalSharedElementState(sharedElements, sharedElementArgs);
+
+        ActivityOptions.SharedElementSource sharedElementSource
+                = new ActivityOptions.SharedElementSource() {
             @Override
-            public int getTextureId() {
-                // TODO: move shared elements to a layer and return the texture id
-                recurseHideExitingSharedElements(mContentParent);
-                return 0;
+            public Bundle getSharedElementExitState() {
+                return sharedElementArgs;
+            }
+
+            @Override
+            public void acceptedSharedElements(ArrayList<String> sharedElementNames) {
+                if (sharedElementNames.size() == sharedElements.size()) {
+                    return; // They were all accepted
+                }
+                Transition transition = mTransitionManager.getExitTransition(mContentScene).clone();
+                TransitionManager.beginDelayedTransition(mDecor, transition);
+                for (String name: sharedElements.keySet()) {
+                    if (!sharedElementNames.contains(name)) {
+                        sharedElements.get(name).setVisibility(View.INVISIBLE);
+                    }
+                }
+                sharedElements.keySet().retainAll(sharedElementNames);
+            }
+
+            @Override
+            public void hideSharedElements() {
+                if (sharedElements != null) {
+                    setViewVisibility(sharedElements.values(), View.INVISIBLE);
+                }
+            }
+        };
+
+        activityOptions.updateSceneTransitionAnimation(
+                exitTransition, sharedElementTransition, sharedElementSource);
+    }
+
+    private void captureTerminalSharedElementState(final Map<String, View> sharedElements,
+            final Bundle sharedElementArgs) {
+        mDecor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+            @Override
+            public boolean onPreDraw() {
+                mDecor.getViewTreeObserver().removeOnPreDrawListener(this);
+                int[] tempLoc = new int[2];
+                for (String name : sharedElements.keySet()) {
+                    View sharedElement = sharedElements.get(name);
+                    captureSharedElementState(sharedElement, name, sharedElementArgs, tempLoc);
+                }
+                return true;
             }
         });
-        ViewGroup sceneRoot = getContentScene().getSceneRoot();
-        TransitionManager.beginDelayedTransition(sceneRoot, transition);
-        recurseExitNonSharedElements(mContentParent);
     }
 
-    private static void recurseExitNonSharedElements(ViewGroup viewGroup) {
-        int numChildren = viewGroup.getChildCount();
-        for (int i = 0; i < numChildren; i++) {
-            View child = viewGroup.getChildAt(i);
-            if (child.getSharedElementName() != null || (child.getVisibility() != View.VISIBLE)) {
-                continue;
-            }
-            if (child instanceof ViewGroup && !((ViewGroup)child).isTransitionGroup()) {
-                recurseExitNonSharedElements((ViewGroup) child);
+    private static Transition cloneAndSetTransitionTargets(Transition transition,
+            List<View> views, boolean add) {
+        transition = transition.clone();
+        if (!transition.getTargetIds().isEmpty() || !transition.getTargets().isEmpty()) {
+            TransitionSet set = new TransitionSet();
+            set.addTransition(transition);
+            transition = set;
+        }
+        for (View view: views) {
+            if (add) {
+                transition.addTarget(view);
             } else {
-                child.setVisibility(View.INVISIBLE);
+                transition.excludeTarget(view, true);
             }
         }
+        return transition;
+    }
+
+    private static void setViewVisibility(Collection<View> views, int visibility) {
+        for (View view : views) {
+            view.setVisibility(visibility);
+        }
     }
 
-    private static void recurseHideViews(ViewGroup viewGroup, ArrayList<View> nonSharedElements,
-            ArrayList<View> sharedElements) {
-        int numChildren = viewGroup.getChildCount();
-        for (int i = 0; i < numChildren; i++) {
-            View child = viewGroup.getChildAt(i);
-            if (child.getVisibility() != View.VISIBLE) {
-                continue;
-            }
-            if (child.getSharedElementName() != null) {
-                sharedElements.add(child);
-                child.setVisibility(View.INVISIBLE);
-            } else if (child instanceof ViewGroup && !((ViewGroup)child).isTransitionGroup()) {
-                recurseHideViews((ViewGroup) child, nonSharedElements, sharedElements);
-            } else {
-                nonSharedElements.add(child);
-                child.setVisibility(View.INVISIBLE);
-            }
+    /**
+     * Sets the captured values from a previous
+     * {@link #captureSharedElementState(android.view.View, String, android.os.Bundle, int[])}
+     * @param view The View to apply placement changes to.
+     * @param name The shared element name given from the source Activity.
+     * @param transitionArgs A <code>Bundle</code> containing all placementinformation for named
+     *                       shared elements in the scene.
+     * @param tempLoc A temporary int[2] for capturing the current location of views.
+     */
+    private static void setSharedElementState(View view, String name, Bundle transitionArgs,
+            int[] tempLoc) {
+        Bundle sharedElementBundle = transitionArgs.getBundle(name);
+        if (sharedElementBundle == null) {
+            return;
         }
+
+        int x = sharedElementBundle.getInt(KEY_SCREEN_X);
+        view.getLocationOnScreen(tempLoc);
+        int offsetX = x - tempLoc[0];
+        view.offsetLeftAndRight(offsetX);
+
+        int width = sharedElementBundle.getInt(KEY_WIDTH);
+        view.setRight(view.getLeft() + width);
+
+        int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
+        int offsetY = y - tempLoc[1];
+        view.offsetTopAndBottom(offsetY);
+
+        int height = sharedElementBundle.getInt(KEY_HEIGHT);
+        view.setBottom(view.getTop() + height);
+
+        float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
+        view.setTranslationZ(z);
     }
 
-    private static void recurseHideExitingSharedElements(ViewGroup viewGroup) {
-        int numChildren = viewGroup.getChildCount();
-        for (int i = 0; i < numChildren; i++) {
-            View child = viewGroup.getChildAt(i);
-            if (child.getVisibility() != View.VISIBLE) {
-                continue;
-            }
-            if (child.getSharedElementName() != null) {
-                child.setVisibility(View.INVISIBLE);
-            } else if (child instanceof ViewGroup) {
-                ViewGroup childViewGroup = (ViewGroup) child;
-                recurseHideExitingSharedElements(childViewGroup);
-            }
-        }
+    /**
+     * Captures placement information for Views with a shared element name for
+     * Activity Transitions.
+     * @param view The View to capture the placement information for.
+     * @param name The shared element name in the target Activity to apply the placement
+     *             information for.
+     * @param transitionArgs Bundle to store shared element placement information.
+     * @param tempLoc A temporary int[2] for capturing the current location of views.
+     * @see #setSharedElementState(android.view.View, String, android.os.Bundle, int[])
+     */
+    private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
+            int[] tempLoc) {
+        Bundle sharedElementBundle = new Bundle();
+        view.getLocationOnScreen(tempLoc);
+        float scaleX = view.getScaleX();
+        sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
+        int width = Math.round(view.getWidth() * scaleX);
+        sharedElementBundle.putInt(KEY_WIDTH, width);
+
+        float scaleY = view.getScaleY();
+        sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
+        int height= Math.round(view.getHeight() * scaleY);
+        sharedElementBundle.putInt(KEY_HEIGHT, height);
+
+        sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
+
+        sharedElementBundle.putString(KEY_NAME, view.getSharedElementName());
+
+        transitionArgs.putBundle(name, sharedElementBundle);
     }
 
     /**
@@ -4080,46 +4234,57 @@
         private boolean mAllDone;
         private Handler mHandler = new Handler();
         private boolean mEnterTransitionStarted;
-        private ArrayList<View> mSharedElements = new ArrayList<View>();
+        private ArrayMap<String, View> mSharedElementTargets = new ArrayMap<String, View>();
+        private ArrayList<View> mEnteringViews = new ArrayList<View>();
 
         public EnterScene() {
             mSceneTransitionListener.nullPendingTransition();
             Drawable background = getDecorView().getBackground();
             if (background != null) {
-                setBackgroundDrawable(null);
                 background.setAlpha(0);
-                setBackgroundDrawable(background);
+                mDecor.drawableChanged();
             }
             mSceneTransitionListener.convertToTranslucent();
         }
 
         @Override
         public boolean onPreDraw() {
-            ViewTreeObserver observer = mContentParent.getViewTreeObserver();
+            ViewTreeObserver observer = mDecor.getViewTreeObserver();
             observer.removeOnPreDrawListener(this);
             if (!mEnterTransitionStarted && mSceneTransitionListener != null) {
                 mEnterTransitionStarted = true;
-                ArrayList<View> enteringViews = new ArrayList<View>();
-                recurseHideViews(mContentParent, enteringViews, mSharedElements);
-                Transition transition = getTransitionManager().getNamedTransition("null",
-                        mContentScene);
-                if (transition == null) {
-                    transition = TransitionManager.getDefaultTransition().clone();
+                mDecor.captureTransitioningViews(mEnteringViews);
+                ArrayList<String> sharedElementNames = mActivityOptions.getSharedElementNames();
+                if (sharedElementNames != null) {
+                    mDecor.findSharedElements(mSharedElementTargets);
+                    if (mSharedElementsMap != null) {
+                        for (Map.Entry<String, String> entry : mSharedElementsMap.entrySet()) {
+                            View sharedElement = mSharedElementTargets.remove(entry.getValue());
+                            if (sharedElement != null) {
+                                mSharedElementTargets.put(entry.getKey(), sharedElement);
+                            }
+                        }
+                    }
+                    mSharedElementTargets.keySet().retainAll(sharedElementNames);
+                    mEnteringViews.removeAll(mSharedElementTargets.values());
                 }
-                TransitionManager.beginDelayedTransition(mContentParent, transition);
-                for (View hidden : enteringViews) {
-                    hidden.setVisibility(View.VISIBLE);
+
+                setViewVisibility(mEnteringViews, View.INVISIBLE);
+                setViewVisibility(mSharedElementTargets.values(), View.INVISIBLE);
+                if (mTriggerEarly) {
+                    beginEnterScene();
                 }
                 observer.addOnPreDrawListener(this);
             } else {
                 mHandler.postDelayed(this, MAX_TRANSITION_START_WAIT);
-                mActivityOptions.dispatchSceneTransitionStarted(this);
+                mActivityOptions.dispatchSceneTransitionStarted(this,
+                        new ArrayList<String>(mSharedElementTargets.keySet()));
             }
             return true;
         }
 
         public void start() {
-            ViewTreeObserver observer = mContentParent.getViewTreeObserver();
+            ViewTreeObserver observer = mDecor.getViewTreeObserver();
             observer.addOnPreDrawListener(this);
         }
 
@@ -4129,25 +4294,43 @@
         }
 
         @Override
-        public void sharedElementTransitionComplete() {
+        public void sharedElementTransitionComplete(Bundle transitionArgs) {
             if (!mSharedElementReadyReceived) {
                 mSharedElementReadyReceived = true;
                 mHandler.removeCallbacks(this);
                 mHandler.postDelayed(this, MAX_TRANSITION_FINISH_WAIT);
-                for (View sharedElement: mSharedElements) {
-                    sharedElement.setVisibility(View.VISIBLE);
-                }
-                mSharedElements.clear();
-                mContentParent.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-                    @Override
-                    public boolean onPreDraw() {
-                        mContentParent.getViewTreeObserver().removeOnPreDrawListener(this);
-                        mSceneTransitionListener.enterSharedElement(
-                                mActivityOptions.getSceneTransitionArgs());
-                        return false;
+                if (!mSharedElementTargets.isEmpty()) {
+                    Transition transition = getTransitionManager().getEnterTransition(
+                            mContentScene);
+                    if (transition == null) {
+                        transition = TransitionManager.getDefaultTransition();
                     }
-                });
-                if (mFadeEarly) {
+                    transition = transition.clone();
+                    if (transitionArgs == null) {
+                        TransitionManager.beginDelayedTransition(mDecor, transition);
+                        setViewVisibility(mSharedElementTargets.values(), View.VISIBLE);
+                    } else {
+                        int[] tempLoc = new int[2];
+                        for (Map.Entry<String, View> entry: mSharedElementTargets.entrySet()) {
+                            setSharedElementState(entry.getValue(), entry.getKey(), transitionArgs,
+                                    tempLoc);
+                        }
+                        setViewVisibility(mSharedElementTargets.values(), View.VISIBLE);
+                        mSceneTransitionListener.sharedElementStart(transition);
+                        mDecor.getViewTreeObserver().addOnPreDrawListener(
+                                new ViewTreeObserver.OnPreDrawListener() {
+                                    @Override
+                                    public boolean onPreDraw() {
+                                        mDecor.getViewTreeObserver().removeOnPreDrawListener(this);
+                                        mSceneTransitionListener.sharedElementEnd();
+                                        mActivityOptions.dispatchSharedElementsReady();
+                                        return true;
+                                    }
+                                });
+                        TransitionManager.beginDelayedTransition(mDecor, transition);
+                    }
+                }
+                if (mTriggerEarly) {
                     fadeInBackground();
                 }
             }
@@ -4170,9 +4353,10 @@
                 return;
             }
             mAllDone = true;
-            sharedElementTransitionComplete();
+            sharedElementTransitionComplete(null);
             mHandler.removeCallbacks(this);
-            if (!mFadeEarly) {
+            if (!mTriggerEarly) {
+                beginEnterScene();
                 fadeInBackground();
             }
         }
@@ -4193,5 +4377,14 @@
         @Override
         public void onAnimationRepeat(Animator animation) {
         }
+
+        private void beginEnterScene() {
+            Transition transition = getTransitionManager().getEnterTransition(mContentScene);
+            if (transition == null) {
+                transition = TransitionManager.getDefaultTransition().clone();
+            }
+            TransitionManager.beginDelayedTransition(mDecor, transition);
+            setViewVisibility(mEnteringViews, View.VISIBLE);
+        }
     }
 }
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 93e839e..55b671d 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -800,8 +800,6 @@
     void updateFromNative() {
         super.updateFromNative();
 
-        // FIXME: updateFromNative is broken in JNI for 64-bit
-
         // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
         int[] dataBuffer = new int[5];
         mRS.nElementGetNativeData(getID(mRS), dataBuffer);
@@ -828,7 +826,7 @@
             mArraySizes = new int[numSubElements];
             mOffsetInBytes = new int[numSubElements];
 
-            int[] subElementIds = new int[numSubElements];
+            long[] subElementIds = new long[numSubElements];
             mRS.nElementGetSubElements(getID(mRS), subElementIds, mElementNames, mArraySizes);
             for(int i = 0; i < numSubElements; i ++) {
                 mElements[i] = new Element(subElementIds[i], mRS);
@@ -1087,10 +1085,9 @@
             java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
             java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
 
-            // FIXME: broken for 64-bit
-            int[] ids = new int[ein.length];
+            long[] ids = new long[ein.length];
             for (int ct = 0; ct < ein.length; ct++ ) {
-                ids[ct] = (int)ein[ct].getID(mRS);
+                ids[ct] = ein[ct].getID(mRS);
             }
             long id = mRS.nElementCreate2(ids, sin, asin);
             return new Element(id, mRS, ein, sin, asin);
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index a4ecc38..1a5dc9e 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -152,8 +152,8 @@
         int vtxCount = mRS.nMeshGetVertexBufferCount(getID(mRS));
         int idxCount = mRS.nMeshGetIndexCount(getID(mRS));
 
-        int[] vtxIDs = new int[vtxCount];
-        int[] idxIDs = new int[idxCount];
+        long[] vtxIDs = new long[vtxCount];
+        long[] idxIDs = new long[idxCount];
         int[] primitives = new int[idxCount];
 
         mRS.nMeshGetVertices(getID(mRS), vtxIDs, vtxCount);
@@ -348,8 +348,8 @@
         **/
         public Mesh create() {
             mRS.validate();
-            int[] vtx = new int[mVertexTypeCount];
-            int[] idx = new int[mIndexTypes.size()];
+            long[] vtx = new long[mVertexTypeCount];
+            long[] idx = new long[mIndexTypes.size()];
             int[] prim = new int[mIndexTypes.size()];
 
             Allocation[] vertexBuffers = new Allocation[mVertexTypeCount];
@@ -365,7 +365,7 @@
                     alloc = Allocation.createSized(mRS, entry.e, entry.size, mUsage);
                 }
                 vertexBuffers[ct] = alloc;
-                vtx[ct] = (int)alloc.getID(mRS);
+                vtx[ct] = alloc.getID(mRS);
             }
 
             for(int ct = 0; ct < mIndexTypes.size(); ct ++) {
@@ -380,7 +380,7 @@
                 indexBuffers[ct] = alloc;
                 primitives[ct] = entry.prim;
 
-                idx[ct] = (int)allocID;
+                idx[ct] = allocID;
                 prim[ct] = entry.prim.mID;
             }
 
@@ -504,8 +504,8 @@
         public Mesh create() {
             mRS.validate();
 
-            int[] vtx = new int[mVertexTypeCount];
-            int[] idx = new int[mIndexTypes.size()];
+            long[] vtx = new long[mVertexTypeCount];
+            long[] idx = new long[mIndexTypes.size()];
             int[] prim = new int[mIndexTypes.size()];
 
             Allocation[] indexBuffers = new Allocation[mIndexTypes.size()];
@@ -515,7 +515,7 @@
             for(int ct = 0; ct < mVertexTypeCount; ct ++) {
                 Entry entry = mVertexTypes[ct];
                 vertexBuffers[ct] = entry.a;
-                vtx[ct] = (int)entry.a.getID(mRS);
+                vtx[ct] = entry.a.getID(mRS);
             }
 
             for(int ct = 0; ct < mIndexTypes.size(); ct ++) {
@@ -524,7 +524,7 @@
                 indexBuffers[ct] = entry.a;
                 primitives[ct] = entry.prim;
 
-                idx[ct] = (int)allocID;
+                idx[ct] = allocID;
                 prim[ct] = entry.prim.mID;
             }
 
diff --git a/rs/java/android/renderscript/ProgramFragment.java b/rs/java/android/renderscript/ProgramFragment.java
index 2704130..5f71bd1 100644
--- a/rs/java/android/renderscript/ProgramFragment.java
+++ b/rs/java/android/renderscript/ProgramFragment.java
@@ -62,25 +62,25 @@
          */
         public ProgramFragment create() {
             mRS.validate();
-            int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+            long[] tmp = new long[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
             String[] texNames = new String[mTextureCount];
             int idx = 0;
 
             for (int i=0; i < mInputCount; i++) {
                 tmp[idx++] = ProgramParam.INPUT.mID;
-                tmp[idx++] = (int)mInputs[i].getID(mRS);
+                tmp[idx++] = mInputs[i].getID(mRS);
             }
             for (int i=0; i < mOutputCount; i++) {
                 tmp[idx++] = ProgramParam.OUTPUT.mID;
-                tmp[idx++] = (int)mOutputs[i].getID(mRS);
+                tmp[idx++] = mOutputs[i].getID(mRS);
             }
             for (int i=0; i < mConstantCount; i++) {
                 tmp[idx++] = ProgramParam.CONSTANT.mID;
-                tmp[idx++] = (int)mConstants[i].getID(mRS);
+                tmp[idx++] = mConstants[i].getID(mRS);
             }
             for (int i=0; i < mTextureCount; i++) {
                 tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
-                tmp[idx++] = (int)mTextureTypes[i].mID;
+                tmp[idx++] = mTextureTypes[i].mID;
                 texNames[i] = mTextureNames[i];
             }
 
diff --git a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
index e1c35c5..2b647c76 100644
--- a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
+++ b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
@@ -49,25 +49,25 @@
          */
         public ProgramFragmentFixedFunction create() {
             mRS.validate();
-            int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+            long[] tmp = new long[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
             String[] texNames = new String[mTextureCount];
             int idx = 0;
 
             for (int i=0; i < mInputCount; i++) {
                 tmp[idx++] = ProgramParam.INPUT.mID;
-                tmp[idx++] = (int)mInputs[i].getID(mRS);
+                tmp[idx++] = mInputs[i].getID(mRS);
             }
             for (int i=0; i < mOutputCount; i++) {
                 tmp[idx++] = ProgramParam.OUTPUT.mID;
-                tmp[idx++] = (int)mOutputs[i].getID(mRS);
+                tmp[idx++] = mOutputs[i].getID(mRS);
             }
             for (int i=0; i < mConstantCount; i++) {
                 tmp[idx++] = ProgramParam.CONSTANT.mID;
-                tmp[idx++] = (int)mConstants[i].getID(mRS);
+                tmp[idx++] = mConstants[i].getID(mRS);
             }
             for (int i=0; i < mTextureCount; i++) {
                 tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
-                tmp[idx++] = (int)mTextureTypes[i].mID;
+                tmp[idx++] = mTextureTypes[i].mID;
                 texNames[i] = mTextureNames[i];
             }
 
diff --git a/rs/java/android/renderscript/ProgramVertex.java b/rs/java/android/renderscript/ProgramVertex.java
index d194ba9..0d7e2d9c 100644
--- a/rs/java/android/renderscript/ProgramVertex.java
+++ b/rs/java/android/renderscript/ProgramVertex.java
@@ -122,25 +122,25 @@
          */
         public ProgramVertex create() {
             mRS.validate();
-            int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+            long[] tmp = new long[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
             String[] texNames = new String[mTextureCount];
             int idx = 0;
 
             for (int i=0; i < mInputCount; i++) {
                 tmp[idx++] = ProgramParam.INPUT.mID;
-                tmp[idx++] = (int)mInputs[i].getID(mRS);
+                tmp[idx++] = mInputs[i].getID(mRS);
             }
             for (int i=0; i < mOutputCount; i++) {
                 tmp[idx++] = ProgramParam.OUTPUT.mID;
-                tmp[idx++] = (int)mOutputs[i].getID(mRS);
+                tmp[idx++] = mOutputs[i].getID(mRS);
             }
             for (int i=0; i < mConstantCount; i++) {
                 tmp[idx++] = ProgramParam.CONSTANT.mID;
-                tmp[idx++] = (int)mConstants[i].getID(mRS);
+                tmp[idx++] = mConstants[i].getID(mRS);
             }
             for (int i=0; i < mTextureCount; i++) {
                 tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
-                tmp[idx++] = (int)mTextureTypes[i].mID;
+                tmp[idx++] = mTextureTypes[i].mID;
                 texNames[i] = mTextureNames[i];
             }
 
diff --git a/rs/java/android/renderscript/ProgramVertexFixedFunction.java b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
index 2d281b8..5173af2 100644
--- a/rs/java/android/renderscript/ProgramVertexFixedFunction.java
+++ b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
@@ -75,25 +75,25 @@
          */
         public ProgramVertexFixedFunction create() {
             mRS.validate();
-            int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+            long[] tmp = new long[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
             String[] texNames = new String[mTextureCount];
             int idx = 0;
 
             for (int i=0; i < mInputCount; i++) {
                 tmp[idx++] = ProgramParam.INPUT.mID;
-                tmp[idx++] = (int)mInputs[i].getID(mRS);
+                tmp[idx++] = mInputs[i].getID(mRS);
             }
             for (int i=0; i < mOutputCount; i++) {
                 tmp[idx++] = ProgramParam.OUTPUT.mID;
-                tmp[idx++] = (int)mOutputs[i].getID(mRS);
+                tmp[idx++] = mOutputs[i].getID(mRS);
             }
             for (int i=0; i < mConstantCount; i++) {
                 tmp[idx++] = ProgramParam.CONSTANT.mID;
-                tmp[idx++] = (int)mConstants[i].getID(mRS);
+                tmp[idx++] = mConstants[i].getID(mRS);
             }
             for (int i=0; i < mTextureCount; i++) {
                 tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
-                tmp[idx++] = (int)mTextureTypes[i].mID;
+                tmp[idx++] = mTextureTypes[i].mID;
                 texNames[i] = mTextureNames[i];
             }
 
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 89dba9f..4dd6045 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -303,8 +303,8 @@
         validate();
         return rsnElementCreate(mContext, type, kind, norm, vecSize);
     }
-    native long rsnElementCreate2(long con, int[]elements, String[] names, int[] arraySizes);
-    synchronized long nElementCreate2(int[] elements, String[] names, int[] arraySizes) {
+    native long rsnElementCreate2(long con, long[] elements, String[] names, int[] arraySizes);
+    synchronized long nElementCreate2(long[] elements, String[] names, int[] arraySizes) {
         validate();
         return rsnElementCreate2(mContext, elements, names, arraySizes);
     }
@@ -314,8 +314,8 @@
         rsnElementGetNativeData(mContext, id, elementData);
     }
     native void rsnElementGetSubElements(long con, long id,
-                                         int[] IDs, String[] names, int[] arraySizes);
-    synchronized void nElementGetSubElements(long id, int[] IDs, String[] names, int[] arraySizes) {
+                                         long[] IDs, String[] names, int[] arraySizes);
+    synchronized void nElementGetSubElements(long id, long[] IDs, String[] names, int[] arraySizes) {
         validate();
         rsnElementGetSubElements(mContext, id, IDs, names, arraySizes);
     }
@@ -325,14 +325,14 @@
         validate();
         return rsnTypeCreate(mContext, eid, x, y, z, mips, faces, yuv);
     }
-    native void rsnTypeGetNativeData(long con, long id, int[] typeData);
-    synchronized void nTypeGetNativeData(long id, int[] typeData) {
+    native void rsnTypeGetNativeData(long con, long id, long[] typeData);
+    synchronized void nTypeGetNativeData(long id, long[] typeData) {
         validate();
         rsnTypeGetNativeData(mContext, id, typeData);
     }
 
-    native long rsnAllocationCreateTyped(long con, long type, int mip, int usage, int pointer);
-    synchronized long nAllocationCreateTyped(long type, int mip, int usage, int pointer) {
+    native long rsnAllocationCreateTyped(long con, long type, int mip, int usage, long pointer);
+    synchronized long nAllocationCreateTyped(long type, int mip, int usage, long pointer) {
         validate();
         return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
     }
@@ -700,8 +700,8 @@
         return rsnScriptFieldIDCreate(mContext, sid, slot);
     }
 
-    native long rsnScriptGroupCreate(long con, int[] kernels, int[] src, int[] dstk, int[] dstf, int[] types);
-    synchronized long nScriptGroupCreate(int[] kernels, int[] src, int[] dstk, int[] dstf, int[] types) {
+    native long rsnScriptGroupCreate(long con, long[] kernels, long[] src, long[] dstk, long[] dstf, long[] types);
+    synchronized long nScriptGroupCreate(long[] kernels, long[] src, long[] dstk, long[] dstf, long[] types) {
         validate();
         return rsnScriptGroupCreate(mContext, kernels, src, dstk, dstf, types);
     }
@@ -764,19 +764,19 @@
         validate();
         rsnProgramBindSampler(mContext, vpf, slot, s);
     }
-    native long rsnProgramFragmentCreate(long con, String shader, String[] texNames, int[] params);
-    synchronized long nProgramFragmentCreate(String shader, String[] texNames, int[] params) {
+    native long rsnProgramFragmentCreate(long con, String shader, String[] texNames, long[] params);
+    synchronized long nProgramFragmentCreate(String shader, String[] texNames, long[] params) {
         validate();
         return rsnProgramFragmentCreate(mContext, shader, texNames, params);
     }
-    native long rsnProgramVertexCreate(long con, String shader, String[] texNames, int[] params);
-    synchronized long nProgramVertexCreate(String shader, String[] texNames, int[] params) {
+    native long rsnProgramVertexCreate(long con, String shader, String[] texNames, long[] params);
+    synchronized long nProgramVertexCreate(String shader, String[] texNames, long[] params) {
         validate();
         return rsnProgramVertexCreate(mContext, shader, texNames, params);
     }
 
-    native long rsnMeshCreate(long con, int[] vtx, int[] idx, int[] prim);
-    synchronized long nMeshCreate(int[] vtx, int[] idx, int[] prim) {
+    native long rsnMeshCreate(long con, long[] vtx, long[] idx, int[] prim);
+    synchronized long nMeshCreate(long[] vtx, long[] idx, int[] prim) {
         validate();
         return rsnMeshCreate(mContext, vtx, idx, prim);
     }
@@ -790,13 +790,13 @@
         validate();
         return rsnMeshGetIndexCount(mContext, id);
     }
-    native void rsnMeshGetVertices(long con, long id, int[] vtxIds, int vtxIdCount);
-    synchronized void nMeshGetVertices(long id, int[] vtxIds, int vtxIdCount) {
+    native void rsnMeshGetVertices(long con, long id, long[] vtxIds, int vtxIdCount);
+    synchronized void nMeshGetVertices(long id, long[] vtxIds, int vtxIdCount) {
         validate();
         rsnMeshGetVertices(mContext, id, vtxIds, vtxIdCount);
     }
-    native void rsnMeshGetIndices(long con, long id, int[] idxIds, int[] primitives, int vtxIdCount);
-    synchronized void nMeshGetIndices(long id, int[] idxIds, int[] primitives, int vtxIdCount) {
+    native void rsnMeshGetIndices(long con, long id, long[] idxIds, int[] primitives, int vtxIdCount);
+    synchronized void nMeshGetIndices(long id, long[] idxIds, int[] primitives, int vtxIdCount) {
         validate();
         rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
     }
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index f1a7273..51c838f 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -379,7 +379,6 @@
          * @return ScriptGroup The new ScriptGroup
          */
         public ScriptGroup create() {
-            // FIXME: this is broken for 64-bit
 
             if (mNodes.size() == 0) {
                 throw new RSInvalidStateException("Empty script groups are not allowed");
@@ -394,13 +393,13 @@
             ArrayList<IO> inputs = new ArrayList<IO>();
             ArrayList<IO> outputs = new ArrayList<IO>();
 
-            int[] kernels = new int[mKernelCount];
+            long[] kernels = new long[mKernelCount];
             int idx = 0;
             for (int ct=0; ct < mNodes.size(); ct++) {
                 Node n = mNodes.get(ct);
                 for (int ct2=0; ct2 < n.mKernels.size(); ct2++) {
                     final Script.KernelID kid = n.mKernels.get(ct2);
-                    kernels[idx++] = (int)kid.getID(mRS);
+                    kernels[idx++] = kid.getID(mRS);
 
                     boolean hasInput = false;
                     boolean hasOutput = false;
@@ -427,21 +426,21 @@
                 throw new RSRuntimeException("Count mismatch, should not happen.");
             }
 
-            int[] src = new int[mLines.size()];
-            int[] dstk = new int[mLines.size()];
-            int[] dstf = new int[mLines.size()];
-            int[] types = new int[mLines.size()];
+            long[] src = new long[mLines.size()];
+            long[] dstk = new long[mLines.size()];
+            long[] dstf = new long[mLines.size()];
+            long[] types = new long[mLines.size()];
 
             for (int ct=0; ct < mLines.size(); ct++) {
                 ConnectLine cl = mLines.get(ct);
-                src[ct] = (int)cl.mFrom.getID(mRS);
+                src[ct] = cl.mFrom.getID(mRS);
                 if (cl.mToK != null) {
-                    dstk[ct] = (int)cl.mToK.getID(mRS);
+                    dstk[ct] = cl.mToK.getID(mRS);
                 }
                 if (cl.mToF != null) {
-                    dstf[ct] = (int)cl.mToF.getID(mRS);
+                    dstf[ct] = cl.mToF.getID(mRS);
                 }
-                types[ct] = (int)cl.mAllocationType.getID(mRS);
+                types[ct] = cl.mAllocationType.getID(mRS);
             }
 
             long id = mRS.nScriptGroupCreate(kernels, src, dstk, dstf, types);
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index 83bf4a5..98aeaa9 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -190,20 +190,18 @@
 
     @Override
     void updateFromNative() {
-        // FIXME: rsaTypeGetNativeData needs 32-bit and 64-bit paths
-
-        // We have 6 integer to obtain mDimX; mDimY; mDimZ;
+        // We have 6 integer/long to obtain mDimX; mDimY; mDimZ;
         // mDimLOD; mDimFaces; mElement;
-        int[] dataBuffer = new int[6];
-        mRS.nTypeGetNativeData((int)getID(mRS), dataBuffer);
+        long[] dataBuffer = new long[6];
+        mRS.nTypeGetNativeData(getID(mRS), dataBuffer);
 
-        mDimX = dataBuffer[0];
-        mDimY = dataBuffer[1];
-        mDimZ = dataBuffer[2];
+        mDimX = (int)dataBuffer[0];
+        mDimY = (int)dataBuffer[1];
+        mDimZ = (int)dataBuffer[2];
         mDimMipmaps = dataBuffer[3] == 1 ? true : false;
         mDimFaces = dataBuffer[4] == 1 ? true : false;
 
-        int elementID = dataBuffer[5];
+        long elementID = dataBuffer[5];
         if(elementID != 0) {
             mElement = new Element(elementID, mRS);
             mElement.updateFromNative();
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index cbb5b3b..07933b4 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -23,8 +23,7 @@
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
 	frameworks/rs \
-	$(rs_generated_include_dir) \
-	$(call include-path-for, corecg graphics)
+	$(rs_generated_include_dir)
 
 LOCAL_CFLAGS += -Wno-unused-parameter
 
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 80a5da2..b547706 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -23,10 +23,7 @@
 #include <math.h>
 #include <utils/misc.h>
 
-#include <core/SkBitmap.h>
-#include <core/SkPixelRef.h>
-#include <core/SkStream.h>
-#include <core/SkTemplates.h>
+#include <SkBitmap.h>
 
 #include <androidfw/Asset.h>
 #include <androidfw/AssetManager.h>
@@ -412,13 +409,21 @@
 
 static jlong
 nElementCreate2(JNIEnv *_env, jobject _this, jlong con,
-                jintArray _ids, jobjectArray _names, jintArray _arraySizes)
+                jlongArray _ids, jobjectArray _names, jintArray _arraySizes)
 {
     int fieldCount = _env->GetArrayLength(_ids);
     LOG_API("nElementCreate2, con(%p)", (RsContext)con);
 
-    jint *ids = _env->GetIntArrayElements(_ids, NULL);
-    jint *arraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
+    jlong *jIds = _env->GetLongArrayElements(_ids, NULL);
+    jint *jArraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
+
+    RsElement *ids = (RsElement*)malloc(fieldCount * sizeof(RsElement));
+    uint32_t *arraySizes = (uint32_t *)malloc(fieldCount * sizeof(uint32_t));
+
+    for(int i = 0; i < fieldCount; i ++) {
+        ids[i] = (RsElement)jIds[i];
+        arraySizes[i] = (uint32_t)jArraySizes[i];
+    }
 
     AutoJavaStringArrayToUTF8 names(_env, _names, fieldCount);
 
@@ -426,12 +431,15 @@
     size_t *sizeArray = names.c_str_len();
 
     jlong id = (jlong)rsElementCreate2((RsContext)con,
-                                     (RsElement *)ids, fieldCount,
+                                     (const RsElement *)ids, fieldCount,
                                      nameArray, fieldCount * sizeof(size_t),  sizeArray,
                                      (const uint32_t *)arraySizes, fieldCount);
 
-    _env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT);
-    _env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT);
+    free(ids);
+    free(arraySizes);
+    _env->ReleaseLongArrayElements(_ids, jIds, JNI_ABORT);
+    _env->ReleaseIntArrayElements(_arraySizes, jArraySizes, JNI_ABORT);
+
     return (jlong)id;
 }
 
@@ -448,30 +456,33 @@
     rsaElementGetNativeData((RsContext)con, (RsElement)id, elementData, dataSize);
 
     for(jint i = 0; i < dataSize; i ++) {
-        _env->SetIntArrayRegion(_elementData, i, 1, (const jint*)&elementData[i]);
+        const jint data = (jint)elementData[i];
+        _env->SetIntArrayRegion(_elementData, i, 1, &data);
     }
 }
 
 
 static void
 nElementGetSubElements(JNIEnv *_env, jobject _this, jlong con, jlong id,
-                       jintArray _IDs,
+                       jlongArray _IDs,
                        jobjectArray _names,
                        jintArray _arraySizes)
 {
-    int dataSize = _env->GetArrayLength(_IDs);
+    uint32_t dataSize = _env->GetArrayLength(_IDs);
     LOG_API("nElementGetSubElements, con(%p)", (RsContext)con);
 
-    uint32_t *ids = (uint32_t *)malloc((uint32_t)dataSize * sizeof(uint32_t));
-    const char **names = (const char **)malloc((uint32_t)dataSize * sizeof(const char *));
-    uint32_t *arraySizes = (uint32_t *)malloc((uint32_t)dataSize * sizeof(uint32_t));
+    uintptr_t *ids = (uintptr_t*)malloc(dataSize * sizeof(uintptr_t));
+    const char **names = (const char **)malloc(dataSize * sizeof(const char *));
+    size_t *arraySizes = (size_t *)malloc(dataSize * sizeof(size_t));
 
     rsaElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes, (uint32_t)dataSize);
 
-    for(jint i = 0; i < dataSize; i++) {
+    for(uint32_t i = 0; i < dataSize; i++) {
+        const jlong id = (jlong)ids[i];
+        const jint arraySize = (jint)arraySizes[i];
         _env->SetObjectArrayElement(_names, i, _env->NewStringUTF(names[i]));
-        _env->SetIntArrayRegion(_IDs, i, 1, (const jint*)&ids[i]);
-        _env->SetIntArrayRegion(_arraySizes, i, 1, (const jint*)&arraySizes[i]);
+        _env->SetLongArrayRegion(_IDs, i, 1, &id);
+        _env->SetIntArrayRegion(_arraySizes, i, 1, &arraySize);
     }
 
     free(ids);
@@ -492,7 +503,7 @@
 }
 
 static void
-nTypeGetNativeData(JNIEnv *_env, jobject _this, jlong con, jlong id, jintArray _typeData)
+nTypeGetNativeData(JNIEnv *_env, jobject _this, jlong con, jlong id, jlongArray _typeData)
 {
     // We are packing 6 items: mDimX; mDimY; mDimZ;
     // mDimLOD; mDimFaces; mElement; into typeData
@@ -501,21 +512,22 @@
     assert(elementCount == 6);
     LOG_API("nTypeGetNativeData, con(%p)", (RsContext)con);
 
-    uint32_t typeData[6];
+    uintptr_t typeData[6];
     rsaTypeGetNativeData((RsContext)con, (RsType)id, typeData, 6);
 
     for(jint i = 0; i < elementCount; i ++) {
-        _env->SetIntArrayRegion(_typeData, i, 1, (const jint*)&typeData[i]);
+        const jlong data = (jlong)typeData[i];
+        _env->SetLongArrayRegion(_typeData, i, 1, &data);
     }
 }
 
 // -----------------------------------
 
 static jlong
-nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mips, jint usage, jint pointer)
+nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mips, jint usage, jlong pointer)
 {
     LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", (RsContext)con, (RsElement)type, mips, usage, (void *)pointer);
-    return (jlong) rsAllocationCreateTyped((RsContext)con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer);
+    return (jlong) rsAllocationCreateTyped((RsContext)con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uintptr_t)pointer);
 }
 
 static void
@@ -601,7 +613,7 @@
     const void* ptr = bitmap.getPixels();
     jlong id = (jlong)rsAllocationCreateTyped((RsContext)con,
                                             (RsType)type, (RsAllocationMipmapControl)mip,
-                                            (uint32_t)usage, (size_t)ptr);
+                                            (uint32_t)usage, (uintptr_t)ptr);
     bitmap.unlockPixels();
     return id;
 }
@@ -1196,34 +1208,63 @@
 }
 
 static jlong
-nScriptGroupCreate(JNIEnv *_env, jobject _this, jlong con, jintArray _kernels, jintArray _src,
-    jintArray _dstk, jintArray _dstf, jintArray _types)
+nScriptGroupCreate(JNIEnv *_env, jobject _this, jlong con, jlongArray _kernels, jlongArray _src,
+    jlongArray _dstk, jlongArray _dstf, jlongArray _types)
 {
     LOG_API("nScriptGroupCreate, con(%p)", (RsContext)con);
 
-    jint kernelsLen = _env->GetArrayLength(_kernels) * sizeof(int);
-    jint *kernelsPtr = _env->GetIntArrayElements(_kernels, NULL);
-    jint srcLen = _env->GetArrayLength(_src) * sizeof(int);
-    jint *srcPtr = _env->GetIntArrayElements(_src, NULL);
-    jint dstkLen = _env->GetArrayLength(_dstk) * sizeof(int);
-    jint *dstkPtr = _env->GetIntArrayElements(_dstk, NULL);
-    jint dstfLen = _env->GetArrayLength(_dstf) * sizeof(int);
-    jint *dstfPtr = _env->GetIntArrayElements(_dstf, NULL);
-    jint typesLen = _env->GetArrayLength(_types) * sizeof(int);
-    jint *typesPtr = _env->GetIntArrayElements(_types, NULL);
+    jint kernelsLen = _env->GetArrayLength(_kernels);
+    jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, NULL);
+    RsScriptKernelID* kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
+    for(int i = 0; i < kernelsLen; ++i) {
+        kernelsPtr[i] = (RsScriptKernelID)jKernelsPtr[i];
+    }
 
-    int id = (int)rsScriptGroupCreate((RsContext)con,
-                               (RsScriptKernelID *)kernelsPtr, kernelsLen,
-                               (RsScriptKernelID *)srcPtr, srcLen,
-                               (RsScriptKernelID *)dstkPtr, dstkLen,
-                               (RsScriptFieldID *)dstfPtr, dstfLen,
-                               (RsType *)typesPtr, typesLen);
+    jint srcLen = _env->GetArrayLength(_src);
+    jlong *jSrcPtr = _env->GetLongArrayElements(_src, NULL);
+    RsScriptKernelID* srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
+    for(int i = 0; i < srcLen; ++i) {
+        srcPtr[i] = (RsScriptKernelID)jSrcPtr[i];
+    }
 
-    _env->ReleaseIntArrayElements(_kernels, kernelsPtr, 0);
-    _env->ReleaseIntArrayElements(_src, srcPtr, 0);
-    _env->ReleaseIntArrayElements(_dstk, dstkPtr, 0);
-    _env->ReleaseIntArrayElements(_dstf, dstfPtr, 0);
-    _env->ReleaseIntArrayElements(_types, typesPtr, 0);
+    jint dstkLen = _env->GetArrayLength(_dstk);
+    jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, NULL);
+    RsScriptKernelID* dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
+    for(int i = 0; i < dstkLen; ++i) {
+        dstkPtr[i] = (RsScriptKernelID)jDstkPtr[i];
+    }
+
+    jint dstfLen = _env->GetArrayLength(_dstf);
+    jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, NULL);
+    RsScriptKernelID* dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
+    for(int i = 0; i < dstfLen; ++i) {
+        dstfPtr[i] = (RsScriptKernelID)jDstfPtr[i];
+    }
+
+    jint typesLen = _env->GetArrayLength(_types);
+    jlong *jTypesPtr = _env->GetLongArrayElements(_types, NULL);
+    RsType* typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
+    for(int i = 0; i < typesLen; ++i) {
+        typesPtr[i] = (RsType)jTypesPtr[i];
+    }
+
+    jlong id = (jlong)rsScriptGroupCreate((RsContext)con,
+                               (RsScriptKernelID *)kernelsPtr, kernelsLen * sizeof(RsScriptKernelID),
+                               (RsScriptKernelID *)srcPtr, srcLen * sizeof(RsScriptKernelID),
+                               (RsScriptKernelID *)dstkPtr, dstkLen * sizeof(RsScriptKernelID),
+                               (RsScriptFieldID *)dstfPtr, dstfLen * sizeof(RsScriptKernelID),
+                               (RsType *)typesPtr, typesLen * sizeof(RsType));
+
+    free(kernelsPtr);
+    free(srcPtr);
+    free(dstkPtr);
+    free(dstfPtr);
+    free(typesPtr);
+    _env->ReleaseLongArrayElements(_kernels, jKernelsPtr, 0);
+    _env->ReleaseLongArrayElements(_src, jSrcPtr, 0);
+    _env->ReleaseLongArrayElements(_dstk, jDstkPtr, 0);
+    _env->ReleaseLongArrayElements(_dstf, jDstfPtr, 0);
+    _env->ReleaseLongArrayElements(_types, jTypesPtr, 0);
     return id;
 }
 
@@ -1292,10 +1333,10 @@
 
 static jlong
 nProgramFragmentCreate(JNIEnv *_env, jobject _this, jlong con, jstring shader,
-                       jobjectArray texNames, jintArray params)
+                       jobjectArray texNames, jlongArray params)
 {
     AutoJavaStringToUTF8 shaderUTF(_env, shader);
-    jint *paramPtr = _env->GetIntArrayElements(params, NULL);
+    jlong *jParamPtr = _env->GetLongArrayElements(params, NULL);
     jint paramLen = _env->GetArrayLength(params);
 
     int texCount = _env->GetArrayLength(texNames);
@@ -1305,11 +1346,16 @@
 
     LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", (RsContext)con, paramLen);
 
+    uintptr_t * paramPtr = (uintptr_t*) malloc(sizeof(uintptr_t) * paramLen);
+    for(int i = 0; i < paramLen; ++i) {
+        paramPtr[i] = (uintptr_t)jParamPtr[i];
+    }
     jlong ret = (jlong)rsProgramFragmentCreate((RsContext)con, shaderUTF.c_str(), shaderUTF.length(),
                                              nameArray, texCount, sizeArray,
-                                             (uint32_t *)paramPtr, paramLen);
+                                             paramPtr, paramLen);
 
-    _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
+    free(paramPtr);
+    _env->ReleaseLongArrayElements(params, jParamPtr, JNI_ABORT);
     return ret;
 }
 
@@ -1318,10 +1364,10 @@
 
 static jlong
 nProgramVertexCreate(JNIEnv *_env, jobject _this, jlong con, jstring shader,
-                     jobjectArray texNames, jintArray params)
+                     jobjectArray texNames, jlongArray params)
 {
     AutoJavaStringToUTF8 shaderUTF(_env, shader);
-    jint *paramPtr = _env->GetIntArrayElements(params, NULL);
+    jlong *jParamPtr = _env->GetLongArrayElements(params, NULL);
     jint paramLen = _env->GetArrayLength(params);
 
     LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", (RsContext)con, paramLen);
@@ -1331,11 +1377,17 @@
     const char ** nameArray = names.c_str();
     size_t* sizeArray = names.c_str_len();
 
+    uintptr_t * paramPtr = (uintptr_t*) malloc(sizeof(uintptr_t) * paramLen);
+    for(int i = 0; i < paramLen; ++i) {
+        paramPtr[i] = (uintptr_t)jParamPtr[i];
+    }
+
     jlong ret = (jlong)rsProgramVertexCreate((RsContext)con, shaderUTF.c_str(), shaderUTF.length(),
                                            nameArray, texCount, sizeArray,
-                                           (uint32_t *)paramPtr, paramLen);
+                                           paramPtr, paramLen);
 
-    _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
+    free(paramPtr);
+    _env->ReleaseLongArrayElements(params, jParamPtr, JNI_ABORT);
     return ret;
 }
 
@@ -1416,24 +1468,36 @@
 }
 
 static jlong
-nMeshCreate(JNIEnv *_env, jobject _this, jlong con, jintArray _vtx, jintArray _idx, jintArray _prim)
+nMeshCreate(JNIEnv *_env, jobject _this, jlong con, jlongArray _vtx, jlongArray _idx, jintArray _prim)
 {
     LOG_API("nMeshCreate, con(%p)", (RsContext)con);
 
     jint vtxLen = _env->GetArrayLength(_vtx);
-    jint *vtxPtr = _env->GetIntArrayElements(_vtx, NULL);
+    jlong *jVtxPtr = _env->GetLongArrayElements(_vtx, NULL);
+    RsAllocation* vtxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * vtxLen);
+    for(int i = 0; i < vtxLen; ++i) {
+        vtxPtr[i] = (RsAllocation)(uintptr_t)jVtxPtr[i];
+    }
+
     jint idxLen = _env->GetArrayLength(_idx);
-    jint *idxPtr = _env->GetIntArrayElements(_idx, NULL);
+    jlong *jIdxPtr = _env->GetLongArrayElements(_idx, NULL);
+    RsAllocation* idxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * idxLen);
+    for(int i = 0; i < idxLen; ++i) {
+        idxPtr[i] = (RsAllocation)(uintptr_t)jIdxPtr[i];
+    }
+
     jint primLen = _env->GetArrayLength(_prim);
     jint *primPtr = _env->GetIntArrayElements(_prim, NULL);
 
-    int id = (int)rsMeshCreate((RsContext)con,
+    jlong id = (jlong)rsMeshCreate((RsContext)con,
                                (RsAllocation *)vtxPtr, vtxLen,
                                (RsAllocation *)idxPtr, idxLen,
                                (uint32_t *)primPtr, primLen);
 
-    _env->ReleaseIntArrayElements(_vtx, vtxPtr, 0);
-    _env->ReleaseIntArrayElements(_idx, idxPtr, 0);
+    free(vtxPtr);
+    free(idxPtr);
+    _env->ReleaseLongArrayElements(_vtx, jVtxPtr, 0);
+    _env->ReleaseLongArrayElements(_idx, jIdxPtr, 0);
     _env->ReleaseIntArrayElements(_prim, primPtr, 0);
     return id;
 }
@@ -1457,7 +1521,7 @@
 }
 
 static void
-nMeshGetVertices(JNIEnv *_env, jobject _this, jlong con, jlong mesh, jintArray _ids, int numVtxIDs)
+nMeshGetVertices(JNIEnv *_env, jobject _this, jlong con, jlong mesh, jlongArray _ids, jint numVtxIDs)
 {
     LOG_API("nMeshGetVertices, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
 
@@ -1465,14 +1529,15 @@
     rsaMeshGetVertices((RsContext)con, (RsMesh)mesh, allocs, (uint32_t)numVtxIDs);
 
     for(jint i = 0; i < numVtxIDs; i ++) {
-        _env->SetIntArrayRegion(_ids, i, 1, (const jint*)&allocs[i]);
+        const jlong alloc = (jlong)allocs[i];
+        _env->SetLongArrayRegion(_ids, i, 1, &alloc);
     }
 
     free(allocs);
 }
 
 static void
-nMeshGetIndices(JNIEnv *_env, jobject _this, jlong con, jlong mesh, jintArray _idxIds, jintArray _primitives, int numIndices)
+nMeshGetIndices(JNIEnv *_env, jobject _this, jlong con, jlong mesh, jlongArray _idxIds, jintArray _primitives, jint numIndices)
 {
     LOG_API("nMeshGetVertices, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
 
@@ -1482,8 +1547,10 @@
     rsaMeshGetIndices((RsContext)con, (RsMesh)mesh, allocs, prims, (uint32_t)numIndices);
 
     for(jint i = 0; i < numIndices; i ++) {
-        _env->SetIntArrayRegion(_idxIds, i, 1, (const jint*)&allocs[i]);
-        _env->SetIntArrayRegion(_primitives, i, 1, (const jint*)&prims[i]);
+        const jlong alloc = (jlong)allocs[i];
+        const jint prim = (jint)prims[i];
+        _env->SetLongArrayRegion(_idxIds, i, 1, &alloc);
+        _env->SetIntArrayRegion(_primitives, i, 1, &prim);
     }
 
     free(allocs);
@@ -1536,14 +1603,14 @@
 {"rsnFontCreateFromAsset",        "(JLandroid/content/res/AssetManager;Ljava/lang/String;FI)J",            (void*)nFontCreateFromAsset },
 
 {"rsnElementCreate",                 "(JJIZI)J",                              (void*)nElementCreate },
-{"rsnElementCreate2",                "(J[I[Ljava/lang/String;[I)J",           (void*)nElementCreate2 },
+{"rsnElementCreate2",                "(J[J[Ljava/lang/String;[I)J",           (void*)nElementCreate2 },
 {"rsnElementGetNativeData",          "(JJ[I)V",                               (void*)nElementGetNativeData },
-{"rsnElementGetSubElements",         "(JJ[I[Ljava/lang/String;[I)V",          (void*)nElementGetSubElements },
+{"rsnElementGetSubElements",         "(JJ[J[Ljava/lang/String;[I)V",          (void*)nElementGetSubElements },
 
 {"rsnTypeCreate",                    "(JJIIIZZI)J",                           (void*)nTypeCreate },
-{"rsnTypeGetNativeData",             "(JJ[I)V",                               (void*)nTypeGetNativeData },
+{"rsnTypeGetNativeData",             "(JJ[J)V",                               (void*)nTypeGetNativeData },
 
-{"rsnAllocationCreateTyped",         "(JJIII)J",                               (void*)nAllocationCreateTyped },
+{"rsnAllocationCreateTyped",         "(JJIIJ)J",                               (void*)nAllocationCreateTyped },
 {"rsnAllocationCreateFromBitmap",    "(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCreateFromBitmap },
 {"rsnAllocationCreateBitmapBackedAllocation",    "(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCreateBitmapBackedAllocation },
 {"rsnAllocationCubeCreateFromBitmap","(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCubeCreateFromBitmap },
@@ -1594,7 +1661,7 @@
 {"rsnScriptIntrinsicCreate",         "(JIJ)J",                                (void*)nScriptIntrinsicCreate },
 {"rsnScriptKernelIDCreate",          "(JJII)J",                               (void*)nScriptKernelIDCreate },
 {"rsnScriptFieldIDCreate",           "(JJI)J",                                (void*)nScriptFieldIDCreate },
-{"rsnScriptGroupCreate",             "(J[I[I[I[I[I)J",                        (void*)nScriptGroupCreate },
+{"rsnScriptGroupCreate",             "(J[J[J[J[J[J)J",                        (void*)nScriptGroupCreate },
 {"rsnScriptGroupSetInput",           "(JJJJ)V",                               (void*)nScriptGroupSetInput },
 {"rsnScriptGroupSetOutput",          "(JJJJ)V",                               (void*)nScriptGroupSetOutput },
 {"rsnScriptGroupExecute",            "(JJ)V",                                 (void*)nScriptGroupExecute },
@@ -1605,9 +1672,9 @@
 {"rsnProgramBindTexture",            "(JJIJ)V",                               (void*)nProgramBindTexture },
 {"rsnProgramBindSampler",            "(JJIJ)V",                               (void*)nProgramBindSampler },
 
-{"rsnProgramFragmentCreate",         "(JLjava/lang/String;[Ljava/lang/String;[I)J",              (void*)nProgramFragmentCreate },
+{"rsnProgramFragmentCreate",         "(JLjava/lang/String;[Ljava/lang/String;[J)J",              (void*)nProgramFragmentCreate },
 {"rsnProgramRasterCreate",           "(JZI)J",                                (void*)nProgramRasterCreate },
-{"rsnProgramVertexCreate",           "(JLjava/lang/String;[Ljava/lang/String;[I)J",              (void*)nProgramVertexCreate },
+{"rsnProgramVertexCreate",           "(JLjava/lang/String;[Ljava/lang/String;[J)J",              (void*)nProgramVertexCreate },
 
 {"rsnContextBindRootScript",         "(JI)V",                                 (void*)nContextBindRootScript },
 {"rsnContextBindProgramStore",       "(JI)V",                                 (void*)nContextBindProgramStore },
@@ -1618,12 +1685,12 @@
 {"rsnSamplerCreate",                 "(JIIIIIF)J",                            (void*)nSamplerCreate },
 
 {"rsnPathCreate",                    "(JIZJJF)J",                             (void*)nPathCreate },
-{"rsnMeshCreate",                    "(J[I[I[I)J",                            (void*)nMeshCreate },
+{"rsnMeshCreate",                    "(J[J[J[I)J",                            (void*)nMeshCreate },
 
 {"rsnMeshGetVertexBufferCount",      "(JJ)I",                                 (void*)nMeshGetVertexBufferCount },
 {"rsnMeshGetIndexCount",             "(JJ)I",                                 (void*)nMeshGetIndexCount },
-{"rsnMeshGetVertices",               "(JJ[II)V",                              (void*)nMeshGetVertices },
-{"rsnMeshGetIndices",                "(JJ[I[II)V",                            (void*)nMeshGetIndices },
+{"rsnMeshGetVertices",               "(JJ[JI)V",                              (void*)nMeshGetVertices },
+{"rsnMeshGetIndices",                "(JJ[J[II)V",                            (void*)nMeshGetIndices },
 
 };
 
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index e534a88..f03a8e0 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -492,7 +492,7 @@
 
         PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
-        
+
         mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
                         Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -1283,13 +1283,7 @@
                                 setWakelockWorkSource(alarm.operation, alarm.workSource);
                                 mWakeLock.setUnimportantForLogging(
                                         alarm.operation == mTimeTickSender);
-                                // XXX debugging
-                                /*
-                                Intent intent = alarm.operation.getIntent();
-                                mWakeLock.setTag(intent.getAction() != null ? intent.getAction()
-                                        : (intent.getComponent() != null
-                                                ? intent.getComponent().toShortString() : TAG));
-                                */
+                                mWakeLock.setHistoryTag(alarm.operation.getTag("*alarm*:"));
                                 mWakeLock.acquire();
                             }
                             final InFlight inflight = new InFlight(AlarmManagerService.this,
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 6e72e24..cb5946a 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -108,6 +108,7 @@
     private final Object mLock = new Object();
 
     private BatteryProperties mBatteryProps;
+    private final BatteryProperties mLastBatteryProps = new BatteryProperties();
     private boolean mBatteryLevelCritical;
     private int mLastBatteryStatus;
     private int mLastBatteryHealth;
@@ -281,6 +282,8 @@
                 mBatteryProps = props;
                 // Process the new values.
                 processValuesLocked();
+            } else {
+                mLastBatteryProps.set(props);
             }
         }
     }
@@ -617,6 +620,9 @@
                 String key = args[1];
                 String value = args[2];
                 try {
+                    if (!mUpdatesStopped) {
+                        mLastBatteryProps.set(mBatteryProps);
+                    }
                     boolean update = true;
                     if ("ac".equals(key)) {
                         mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
@@ -649,13 +655,17 @@
             } else if (args.length == 1 && "reset".equals(args[0])) {
                 long ident = Binder.clearCallingIdentity();
                 try {
-                    mUpdatesStopped = false;
+                    if (mUpdatesStopped) {
+                        mUpdatesStopped = false;
+                        mBatteryProps.set(mLastBatteryProps);
+                        processValuesLocked();
+                    }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
             } else {
                 pw.println("Dump current battery state, or:");
-                pw.println("  set ac|usb|wireless|status|level|invalid <value>");
+                pw.println("  set [ac|usb|wireless|status|level|invalid] <value>");
                 pw.println("  reset");
             }
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 36907ed..d5c2a0f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1986,7 +1986,9 @@
         mNetTrackers[prevNetType].setTeardownRequested(false);
 
         // Remove idletimer previously setup in {@code handleConnect}
-        removeDataActivityTracking(prevNetType);
+        if (mNetConfigs[prevNetType].isDefault()) {
+            removeDataActivityTracking(prevNetType);
+        }
 
         /*
          * If the disconnected network is not the active one, then don't report
@@ -2318,8 +2320,6 @@
     private void handleConnect(NetworkInfo info) {
         final int newNetType = info.getType();
 
-        setupDataActivityTracking(newNetType);
-
         // snapshot isFailover, because sendConnectedBroadcast() resets it
         boolean isFailover = info.isFailover();
         final NetworkStateTracker thisNet = mNetTrackers[newNetType];
@@ -2357,6 +2357,7 @@
                         return;
                 }
             }
+            setupDataActivityTracking(newNetType);
             synchronized (ConnectivityService.this) {
                 // have a new default network, release the transition wakelock in a second
                 // if it's held.  The second pause is to allow apps to reconnect over the
@@ -2406,7 +2407,7 @@
      * Setup data activity tracking for the given network interface.
      *
      * Every {@code setupDataActivityTracking} should be paired with a
-     * {@link removeDataActivityTracking} for cleanup.
+     * {@link #removeDataActivityTracking} for cleanup.
      */
     private void setupDataActivityTracking(int type) {
         final NetworkStateTracker thisNet = mNetTrackers[type];
@@ -2431,7 +2432,7 @@
 
         if (timeout > 0 && iface != null) {
             try {
-                mNetd.addIdleTimer(iface, timeout, Integer.toString(type));
+                mNetd.addIdleTimer(iface, timeout, type);
             } catch (RemoteException e) {
             }
         }
@@ -2944,6 +2945,9 @@
             }
         }
 
+        pw.print("Active default network: "); pw.println(getNetworkTypeName(mActiveDefaultNetwork));
+        pw.println();
+
         pw.println("Network Requester Pids:");
         pw.increaseIndent();
         for (int net : mPriorityList) {
@@ -3641,8 +3645,7 @@
             int user = UserHandle.getUserId(Binder.getCallingUid());
             if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) {
                 synchronized(mVpns) {
-                    mVpns.get(user).protect(socket,
-                            mNetTrackers[type].getLinkProperties().getInterfaceName());
+                    mVpns.get(user).protect(socket);
                 }
                 return true;
             }
diff --git a/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java b/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java
index 6fbf713..0cf9dcd 100644
--- a/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java
+++ b/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java
@@ -20,5 +20,6 @@
 interface INativeDaemonConnectorCallbacks {
 
     void onDaemonConnected();
+    boolean onCheckHoldWakeLock(int code);
     boolean onEvent(int code, String raw, String[] cooked);
 }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index fc68205..1eedaae 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1790,10 +1790,6 @@
 
     @Override
     public boolean isProviderEnabled(String provider) {
-        // TODO: remove this check in next release, see b/10696351
-        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
-                provider);
-
         // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
         // so we discourage its use
         if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 607def6..a7ef424 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -817,6 +817,13 @@
     /**
      * Callback from NativeDaemonConnector
      */
+    public boolean onCheckHoldWakeLock(int code) {
+        return false;
+    }
+
+    /**
+     * Callback from NativeDaemonConnector
+     */
     public boolean onEvent(int code, String raw, String[] cooked) {
         if (DEBUG_EVENTS) {
             StringBuilder builder = new StringBuilder();
@@ -1407,7 +1414,8 @@
          * amount of containers we'd ever expect to have. This keeps an
          * "asec list" from blocking a thread repeatedly.
          */
-        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
+        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
+                null);
 
         Thread thread = new Thread(mConnector, VOLD_TAG);
         thread.start();
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 417d6d8..265b957 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -21,6 +21,7 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.SystemClock;
 import android.util.LocalLog;
 import android.util.Slog;
@@ -56,6 +57,8 @@
 
     private final ResponseQueue mResponseQueue;
 
+    private final PowerManager.WakeLock mWakeLock;
+
     private INativeDaemonConnectorCallbacks mCallbacks;
     private Handler mCallbackHandler;
 
@@ -70,10 +73,14 @@
     private final int BUFFER_SIZE = 4096;
 
     NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
-            int responseQueueSize, String logTag, int maxLogSize) {
+            int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {
         mCallbacks = callbacks;
         mSocket = socket;
         mResponseQueue = new ResponseQueue(responseQueueSize);
+        mWakeLock = wl;
+        if (mWakeLock != null) {
+            mWakeLock.setReferenceCounted(true);
+        }
         mSequenceNumber = new AtomicInteger(0);
         TAG = logTag != null ? logTag : "NativeDaemonConnector";
         mLocalLog = new LocalLog(maxLogSize);
@@ -102,6 +109,10 @@
             }
         } catch (Exception e) {
             loge("Error handling '" + event + "': " + e);
+        } finally {
+            if (mCallbacks.onCheckHoldWakeLock(msg.what)) {
+                mWakeLock.release();
+            }
         }
         return true;
     }
@@ -154,18 +165,29 @@
                                 buffer, start, i - start, StandardCharsets.UTF_8);
                         log("RCV <- {" + rawEvent + "}");
 
+                        boolean releaseWl = false;
                         try {
                             final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(
                                     rawEvent);
                             if (event.isClassUnsolicited()) {
                                 // TODO: migrate to sending NativeDaemonEvent instances
-                                mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
-                                        event.getCode(), event.getRawEvent()));
+                                if (mCallbacks.onCheckHoldWakeLock(event.getCode())) {
+                                    mWakeLock.acquire();
+                                    releaseWl = true;
+                                }
+                                if (mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(
+                                        event.getCode(), event.getRawEvent()))) {
+                                    releaseWl = false;
+                                }
                             } else {
                                 mResponseQueue.add(event.getCmdNumber(), event);
                             }
                         } catch (IllegalArgumentException e) {
                             log("Problem parsing message: " + rawEvent + " - " + e);
+                        } finally {
+                            if (releaseWl) {
+                                mWakeLock.acquire();
+                            }
                         }
 
                         start = i + 1;
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 74de577..bfc966b 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -37,6 +37,7 @@
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
 
 import android.content.Context;
+import android.net.ConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
@@ -48,7 +49,9 @@
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -81,7 +84,6 @@
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -175,12 +177,12 @@
     /** Set of interfaces with active idle timers. */
     private static class IdleTimerParams {
         public final int timeout;
-        public final String label;
+        public final int type;
         public int networkCount;
 
-        IdleTimerParams(int timeout, String label) {
+        IdleTimerParams(int timeout, int type) {
             this.timeout = timeout;
-            this.label = label;
+            this.type = type;
             this.networkCount = 1;
         }
     }
@@ -189,6 +191,10 @@
     private volatile boolean mBandwidthControlEnabled;
     private volatile boolean mFirewallEnabled;
 
+    private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
+            new RemoteCallbackList<INetworkActivityListener>();
+    private boolean mNetworkActive;
+
     /**
      * Constructs a new NetworkManagementService instance
      *
@@ -201,8 +207,11 @@
             return;
         }
 
+        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
+
         mConnector = new NativeDaemonConnector(
-                new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160);
+                new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl);
         mThread = new Thread(mConnector, NETD_TAG);
 
         // Add ourself to the Watchdog monitors.
@@ -337,20 +346,38 @@
     /**
      * Notify our observers of a change in the data activity state of the interface
      */
-    private void notifyInterfaceClassActivity(String label, boolean active) {
+    private void notifyInterfaceClassActivity(int type, boolean active) {
         try {
-            getBatteryStats().noteDataConnectionActive(label, active);
+            getBatteryStats().noteDataConnectionActive(type, active);
         } catch (RemoteException e) {
         }
+
         final int length = mObservers.beginBroadcast();
         for (int i = 0; i < length; i++) {
             try {
-                mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(label, active);
+                mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
+                        Integer.toString(type), active);
             } catch (RemoteException e) {
             } catch (RuntimeException e) {
             }
         }
         mObservers.finishBroadcast();
+
+        boolean report = false;
+        synchronized (mIdleTimerLock) {
+            if (mActiveIdleTimers.isEmpty()) {
+                // If there are no idle times, we are not monitoring activity, so we
+                // are always considered active.
+                active = true;
+            }
+            if (mNetworkActive != active) {
+                mNetworkActive = active;
+                report = active;
+            }
+        }
+        if (report) {
+            reportNetworkActive();
+        }
     }
 
     /**
@@ -488,6 +515,11 @@
         }
 
         @Override
+        public boolean onCheckHoldWakeLock(int code) {
+            return code == NetdResponseCode.InterfaceClassActivity;
+        }
+
+        @Override
         public boolean onEvent(int code, String raw, String[] cooked) {
             String errorMessage = String.format("Invalid event from daemon (%s)", raw);
             switch (code) {
@@ -540,7 +572,7 @@
                         throw new IllegalStateException(errorMessage);
                     }
                     boolean isActive = cooked[2].equals("active");
-                    notifyInterfaceClassActivity(cooked[3], isActive);
+                    notifyInterfaceClassActivity(Integer.parseInt(cooked[3]), isActive);
                     return true;
                     // break;
             case NetdResponseCode.InterfaceAddressChange:
@@ -1202,7 +1234,7 @@
     }
 
     @Override
-    public void addIdleTimer(String iface, int timeout, String label) {
+    public void addIdleTimer(String iface, int timeout, final int type) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         if (DBG) Slog.d(TAG, "Adding idletimer");
@@ -1216,13 +1248,22 @@
             }
 
             try {
-                mConnector.execute("idletimer", "add", iface, Integer.toString(timeout), label);
+                mConnector.execute("idletimer", "add", iface, Integer.toString(timeout),
+                        Integer.toString(type));
             } catch (NativeDaemonConnectorException e) {
                 throw e.rethrowAsParcelableException();
             }
-            mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, label));
+            mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
+
             // Networks start up.
-            notifyInterfaceClassActivity(label, true);
+            if (ConnectivityManager.isNetworkTypeMobile(type)) {
+                mNetworkActive = false;
+            }
+            mMainHandler.post(new Runnable() {
+                @Override public void run() {
+                    notifyInterfaceClassActivity(type, true);
+                }
+            });
         }
     }
 
@@ -1233,18 +1274,23 @@
         if (DBG) Slog.d(TAG, "Removing idletimer");
 
         synchronized (mIdleTimerLock) {
-            IdleTimerParams params = mActiveIdleTimers.get(iface);
+            final IdleTimerParams params = mActiveIdleTimers.get(iface);
             if (params == null || --(params.networkCount) > 0) {
                 return;
             }
 
             try {
                 mConnector.execute("idletimer", "remove", iface,
-                        Integer.toString(params.timeout), params.label);
+                        Integer.toString(params.timeout), Integer.toString(params.type));
             } catch (NativeDaemonConnectorException e) {
                 throw e.rethrowAsParcelableException();
             }
             mActiveIdleTimers.remove(iface);
+            mMainHandler.post(new Runnable() {
+                @Override public void run() {
+                    notifyInterfaceClassActivity(params.type, false);
+                }
+            });
         }
     }
 
@@ -1803,6 +1849,35 @@
         return event.getMessage().endsWith("started");
     }
 
+    @Override
+    public void registerNetworkActivityListener(INetworkActivityListener listener) {
+        mNetworkActivityListeners.register(listener);
+    }
+
+    @Override
+    public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
+        mNetworkActivityListeners.unregister(listener);
+    }
+
+    @Override
+    public boolean isNetworkActive() {
+        synchronized (mNetworkActivityListeners) {
+            return mNetworkActive || mActiveIdleTimers.isEmpty();
+        }
+    }
+
+    private void reportNetworkActive() {
+        final int length = mNetworkActivityListeners.beginBroadcast();
+        for (int i = 0; i < length; i++) {
+            try {
+                mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
+            } catch (RemoteException e) {
+            } catch (RuntimeException e) {
+            }
+        }
+        mNetworkActivityListeners.finishBroadcast();
+    }
+
     /** {@inheritDoc} */
     @Override
     public void monitor() {
@@ -1836,6 +1911,17 @@
             pw.println("]");
         }
 
+        synchronized (mIdleTimerLock) {
+            pw.println("Idle timers:");
+            for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
+                pw.print("  "); pw.print(ent.getKey()); pw.println(":");
+                IdleTimerParams params = ent.getValue();
+                pw.print("    timeout="); pw.print(params.timeout);
+                pw.print(" type="); pw.print(params.type);
+                pw.print(" networkCount="); pw.println(params.networkCount);
+            }
+        }
+
         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
     }
 }
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 74633ae..c9f9a25 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -534,7 +534,7 @@
         mContentResolver = context.getContentResolver();
 
         mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
-                MDNS_TAG, 25);
+                MDNS_TAG, 25, null);
 
         mNsdStateMachine = new NsdStateMachine(TAG);
         mNsdStateMachine.start();
@@ -622,6 +622,10 @@
             mNativeDaemonConnected.countDown();
         }
 
+        public boolean onCheckHoldWakeLock(int code) {
+            return false;
+        }
+
         public boolean onEvent(int code, String raw, String[] cooked) {
             // TODO: NDC translates a message to a callback, we could enhance NDC to
             // directly interact with a state machine through messages
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d5c3cb4..3bb1d0d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5547,6 +5547,38 @@
     }
 
     @Override
+    public String getTagForIntentSender(IIntentSender pendingResult, String prefix) {
+        if (!(pendingResult instanceof PendingIntentRecord)) {
+            return null;
+        }
+        try {
+            PendingIntentRecord res = (PendingIntentRecord)pendingResult;
+            Intent intent = res.key.requestIntent;
+            if (intent != null) {
+                if (res.lastTag != null && res.lastTagPrefix == prefix && (res.lastTagPrefix == null
+                        || res.lastTagPrefix.equals(prefix))) {
+                    return res.lastTag;
+                }
+                res.lastTagPrefix = prefix;
+                StringBuilder sb = new StringBuilder(128);
+                if (prefix != null) {
+                    sb.append(prefix);
+                }
+                if (intent.getAction() != null) {
+                    sb.append(intent.getAction());
+                } else if (intent.getComponent() != null) {
+                    intent.getComponent().appendShortString(sb);
+                } else {
+                    sb.append("?");
+                }
+                return res.lastTag = sb.toString();
+            }
+        } catch (ClassCastException e) {
+        }
+        return null;
+    }
+
+    @Override
     public void setProcessLimit(int max) {
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
                 "setProcessLimit()");
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 059aa2b..fc7aac2 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -126,11 +126,11 @@
         }
     }
 
-    public void noteStartWakelock(int uid, int pid, String name, int type,
+    public void noteStartWakelock(int uid, int pid, String name, String historyName, int type,
             boolean unimportantForLogging) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStartWakeLocked(uid, pid, name, type, unimportantForLogging);
+            mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging);
         }
     }
 
@@ -141,11 +141,12 @@
         }
     }
 
-    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type,
-            boolean unimportantForLogging) {
+    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name,
+            String historyName, int type, boolean unimportantForLogging) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStartWakeFromSourceLocked(ws, pid, name, type, unimportantForLogging);
+            mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName,
+                    type, unimportantForLogging);
         }
     }
 
@@ -231,10 +232,10 @@
         }
     }
 
-    public void noteDataConnectionActive(String label, boolean active) {
+    public void noteDataConnectionActive(int type, boolean active) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteDataConnectionActive(label, active);
+            mStats.noteDataConnectionActive(type, active);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 00fa216..98999e9 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -41,6 +41,8 @@
     boolean canceled = false;
 
     String stringName;
+    String lastTagPrefix;
+    String lastTag;
     
     final static class Key {
         final int type;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index af08d57..f4bad73 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -279,13 +279,12 @@
     }
 
     /**
-     * Protect a socket from routing changes by binding it to the given
-     * interface. The socket is NOT closed by this method.
+     * Protect a socket from VPN rules by binding it to the main routing table.
+     * The socket is NOT closed by this method.
      *
      * @param socket The socket to be bound.
-     * @param interfaze The name of the interface.
      */
-    public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
+    public void protect(ParcelFileDescriptor socket) throws Exception {
 
         PackageManager pm = mContext.getPackageManager();
         int appUid = pm.getPackageUid(mPackage, mUserId);
@@ -299,8 +298,6 @@
         } finally {
             Binder.restoreCallingIdentity(token);
         }
-        // bind the socket to the interface
-        jniProtect(socket.getFd(), interfaze);
 
     }
 
@@ -679,7 +676,6 @@
     private native int jniSetRoutes(String interfaze, String routes);
     private native void jniReset(String interfaze);
     private native int jniCheck(String interfaze);
-    private native void jniProtect(int socket, String interfaze);
 
     private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) {
         for (RouteInfo route : prop.getAllRoutes()) {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 0185a21..e43dea9 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -53,6 +53,7 @@
 import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
+import android.os.BatteryStats;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -60,6 +61,7 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -75,6 +77,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.accounts.AccountManagerService;
@@ -151,7 +154,7 @@
 
     private static final int INITIALIZATION_UNBIND_DELAY_MS = 5000;
 
-    private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*";
+    private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*/";
     private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
     private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
 
@@ -172,6 +175,7 @@
 
     private final NotificationManager mNotificationMgr;
     private AlarmManager mAlarmService = null;
+    private final IBatteryStats mBatteryStats;
 
     private SyncStorageEngine mSyncStorageEngine;
 
@@ -435,6 +439,8 @@
         }
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
+                BatteryStats.SERVICE_NAME));
 
         // This WakeLock is used to ensure that we stay awake between the time that we receive
         // a sync alarm notification and when we finish processing it. We need to do this
@@ -1123,6 +1129,7 @@
         final int mSyncAdapterUid;
         SyncInfo mSyncInfo;
         boolean mIsLinkedToDeath = false;
+        String mEventName;
 
         /**
          * Create an ActiveSyncContext for an impending sync and grab the wakelock for that
@@ -1201,6 +1208,13 @@
                     new UserHandle(mSyncOperation.target.userId));
             if (!bindResult) {
                 mBound = false;
+            } else {
+                try {
+                    mEventName = mSyncOperation.wakeLockName();
+                    mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_SYNC_START,
+                            mEventName, mSyncAdapterUid);
+                } catch (RemoteException e) {
+                }
             }
             return bindResult;
         }
@@ -1216,6 +1230,11 @@
             if (mBound) {
                 mBound = false;
                 mContext.unbindService(this);
+                try {
+                    mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_SYNC_FINISH,
+                            mEventName, mSyncAdapterUid);
+                } catch (RemoteException e) {
+                }
             }
             mSyncWakeLock.release();
             mSyncWakeLock.setWorkSource(null);
@@ -1908,10 +1927,10 @@
         }
 
         private PowerManager.WakeLock getSyncWakeLock(SyncOperation operation) {
-            final String wakeLockKey = operation.wakeLockKey();
+            final String wakeLockKey = operation.wakeLockName();
             PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
             if (wakeLock == null) {
-                final String name = SYNC_WAKE_LOCK_PREFIX + operation.wakeLockName();
+                final String name = SYNC_WAKE_LOCK_PREFIX + wakeLockKey;
                 wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
                 wakeLock.setReferenceCounted(false);
                 mWakeLocks.put(wakeLockKey, wakeLock);
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 036b21f..5233014 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -86,6 +86,9 @@
     /** Amount of time before {@link #effectiveRunTime} from which this sync can run. */
     public long flexTime;
 
+    /** Descriptive string key for this operation */
+    public String wakeLockName;
+
     public SyncOperation(Account account, int userId, int reason, int source, String provider,
             Bundle extras, long runTimeFromNow, long flexTime, long backoff,
             long delayUntil, boolean allowParallelSyncs) {
@@ -308,25 +311,17 @@
         sb.append("]");
     }
 
-    public String wakeLockKey() {
-        if (target.target_provider) {
-            return target.account.name + "/" + target.account.type + ":" + target.provider;
-        } else if (target.target_service) {
-            return target.service.getPackageName() + "/" + target.service.getClassName();
-        } else {
-            Log.wtf(TAG, "Invalid target getting wakelock for operation - " + key);
-            return null;
-        }
-    }
-
     public String wakeLockName() {
+        if (wakeLockName != null) {
+            return wakeLockName;
+        }
         if (target.target_provider) {
-            return "/" + target.provider
+            return (wakeLockName = target.provider
                     + "/" + target.account.type
-                    + "/" + target.account.name;
+                    + "/" + target.account.name);
         } else if (target.target_service) {
-            return "/" + target.service.getPackageName()
-                    + "/" + target.service.getClassName();
+            return (wakeLockName = target.service.getPackageName()
+                    + "/" + target.service.getClassName());
         } else {
             Log.wtf(TAG, "Invalid target getting wakelock name for operation - " + key);
             return null;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 0d3fa84..89acec9 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -17,10 +17,10 @@
 package com.android.server.media;
 
 import android.content.Intent;
-import android.media.IMediaController;
-import android.media.IMediaControllerCallback;
-import android.media.IMediaSession;
-import android.media.IMediaSessionCallback;
+import android.media.session.IMediaController;
+import android.media.session.IMediaControllerCallback;
+import android.media.session.IMediaSession;
+import android.media.session.IMediaSessionCallback;
 import android.media.RemoteControlClient;
 import android.os.Bundle;
 import android.os.IBinder;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 9c96c35..a7ff926 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -17,9 +17,9 @@
 package com.android.server.media;
 
 import android.content.Context;
-import android.media.IMediaSession;
-import android.media.IMediaSessionCallback;
-import android.media.IMediaSessionManager;
+import android.media.session.IMediaSession;
+import android.media.session.IMediaSessionCallback;
+import android.media.session.IMediaSessionManager;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.text.TextUtils;
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index df2aaca..243bd74 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -16,6 +16,8 @@
 
 package com.android.server.notification;
 
+import android.os.IBinder;
+
 public interface NotificationDelegate {
     void onSetDisabled(int status);
     void onClearAll();
@@ -24,4 +26,5 @@
     void onNotificationError(String pkg, String tag, int id,
             int uid, int initialPid, String message);
     void onPanelRevealed();
+    boolean allowDisable(int what, IBinder token, String pkg);
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ab46dfe..e37bb9c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -154,7 +154,7 @@
     private long[] mFallbackVibrationPattern;
     boolean mSystemReady;
 
-    int mDisabledNotifications;
+    private boolean mDisableNotificationAlerts;
     NotificationRecord mSoundNotification;
     NotificationRecord mVibrateNotification;
 
@@ -202,6 +202,19 @@
 
     final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
 
+    private int mZenMode;
+    private int mPreZenAlarmVolume = -1;
+    private int mPreZenRingerMode = -1;
+    // temporary, until we update apps to provide metadata
+    private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList(
+            "com.google.android.dialer",
+            "com.android.phone"
+            ));
+    private static final Set<String> ALARM_PACKAGES = new HashSet<String>(Arrays.asList(
+            "com.google.android.deskclock"
+            ));
+    private static final String EXTRA_INTERCEPT = "android.intercept";
+
     private class NotificationListenerInfo implements IBinder.DeathRecipient {
         INotificationListener listener;
         ComponentName component;
@@ -258,10 +271,11 @@
 
         @Override
         public void binderDied() {
-            if (connection == null) {
-                // This is not a service; it won't be recreated. We can give up this connection.
-                unregisterListenerImpl(this.listener, this.userid);
-            }
+            // Remove the listener, but don't unbind from the service. The system will bring the
+            // service back up, and the onServiceConnected handler will readd the listener with the
+            // new binding. If this isn't a bound service, and is just a registered
+            // INotificationListener, just removing it from the list is all we need to do anyway.
+            removeListenerImpl(this.listener, this.userid);
         }
 
         /** convenience method for looking in mEnabledListenersForCurrentUser */
@@ -869,8 +883,8 @@
         @Override
         public void onSetDisabled(int status) {
             synchronized (mNotificationList) {
-                mDisabledNotifications = status;
-                if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
+                mDisableNotificationAlerts = (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
+                if (mDisableNotificationAlerts) {
                     // cancel whatever's going on
                     long identity = Binder.clearCallingIdentity();
                     try {
@@ -968,6 +982,14 @@
             }
             Binder.restoreCallingIdentity(ident);
         }
+
+        @Override
+        public boolean allowDisable(int what, IBinder token, String pkg) {
+            if (mZenMode == Settings.Global.ZEN_MODE_FULL && isCall(pkg, null)) {
+                return false;
+            }
+            return true;
+        }
     };
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@@ -1077,6 +1099,12 @@
         private final Uri ENABLED_NOTIFICATION_LISTENERS_URI
                 = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
 
+        private final Uri ZEN_MODE
+                = Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
+
+        private final Uri MODE_RINGER
+                = Settings.Global.getUriFor(Settings.Global.MODE_RINGER);
+
         SettingsObserver(Handler handler) {
             super(handler);
         }
@@ -1087,6 +1115,10 @@
                     false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
                     false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(ZEN_MODE,
+                    false, this);
+            resolver.registerContentObserver(MODE_RINGER,
+                    false, this);
             update(null);
         }
 
@@ -1107,6 +1139,12 @@
             if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) {
                 rebindListenerServices();
             }
+            if (ZEN_MODE.equals(uri)) {
+                updateZenMode();
+            }
+            if (MODE_RINGER.equals(uri)) {
+                updateRingerMode();
+            }
         }
     }
 
@@ -1170,8 +1208,10 @@
         // flag at least once and we'll go back to 0 after that.
         if (0 == Settings.Global.getInt(getContext().getContentResolver(),
                     Settings.Global.DEVICE_PROVISIONED, 0)) {
-            mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
+            mDisableNotificationAlerts = true;
         }
+        updateRingerMode();
+        updateZenMode();
 
         // register for various Intents
         IntentFilter filter = new IntentFilter();
@@ -1622,8 +1662,10 @@
 
             pw.println("  mSoundNotification=" + mSoundNotification);
             pw.println("  mVibrateNotification=" + mVibrateNotification);
-            pw.println("  mDisabledNotifications=0x"
-                    + Integer.toHexString(mDisabledNotifications));
+            pw.println("  mDisableNotificationAlerts=" + mDisableNotificationAlerts);
+            pw.println("  mZenMode=" + Settings.Global.zenModeToString(mZenMode));
+            pw.println("  mPreZenAlarmVolume=" + mPreZenAlarmVolume);
+            pw.println("  mPreZenRingerMode=" + mPreZenRingerMode);
             pw.println("  mSystemReady=" + mSystemReady);
             pw.println("  mArchive=" + mArchive.toString());
             Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
@@ -1767,9 +1809,13 @@
                     return;
                 }
 
-                // Should this notification make noise, vibe, or use the LED?
-                final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD);
+                // Is this notification intercepted by zen mode?
+                final boolean intercept = shouldIntercept(pkg, notification);
+                notification.extras.putBoolean(EXTRA_INTERCEPT, intercept);
 
+                // Should this notification make noise, vibe, or use the LED?
+                final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD) && !intercept;
+                if (DBG) Slog.v(TAG, "canInterrupt=" + canInterrupt + " intercept=" + intercept);
                 synchronized (mNotificationList) {
                     final StatusBarNotification n = new StatusBarNotification(
                             pkg, id, tag, callingUid, callingPid, score, notification, user);
@@ -1851,8 +1897,7 @@
                     }
 
                     // If we're not supposed to beep, vibrate, etc. then don't.
-                    if (((mDisabledNotifications
-                            & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
+                    if (!mDisableNotificationAlerts
                             && (!(old != null
                                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
                             && (r.getUserId() == UserHandle.USER_ALL ||
@@ -1860,7 +1905,7 @@
                             && canInterrupt
                             && mSystemReady
                             && mAudioManager != null) {
-
+                        if (DBG) Slog.v(TAG, "Interrupting!");
                         // sound
 
                         // should we use the default notification sound? (indicated either by
@@ -1905,6 +1950,8 @@
                                     final IRingtonePlayer player =
                                             mAudioManager.getRingtonePlayer();
                                     if (player != null) {
+                                        if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+                                                + " on stream " + audioStreamType);
                                         player.playAsync(soundUri, user, looping, audioStreamType);
                                     }
                                 } catch (RemoteException e) {
@@ -1999,20 +2046,35 @@
         }
     }
 
+    /**
+     * Removes a listener from the list and unbinds from its service.
+     */
     void unregisterListenerImpl(final INotificationListener listener, final int userid) {
+        NotificationListenerInfo info = removeListenerImpl(listener, userid);
+        if (info != null && info.connection != null) {
+            getContext().unbindService(info.connection);
+        }
+    }
+
+    /**
+     * Removes a listener from the list but does not unbind from the listener's service.
+     *
+     * @return the removed listener.
+     */
+    NotificationListenerInfo removeListenerImpl(
+            final INotificationListener listener, final int userid) {
+        NotificationListenerInfo listenerInfo = null;
         synchronized (mNotificationList) {
             final int N = mListeners.size();
             for (int i=N-1; i>=0; i--) {
                 final NotificationListenerInfo info = mListeners.get(i);
                 if (info.listener.asBinder() == listener.asBinder()
                         && info.userid == userid) {
-                    mListeners.remove(i);
-                    if (info.connection != null) {
-                        getContext().unbindService(info.connection);
-                    }
+                    listenerInfo = mListeners.remove(i);
                 }
             }
         }
+        return listenerInfo;
     }
 
     void showNextToastLocked() {
@@ -2437,4 +2499,67 @@
             updateLightsLocked();
         }
     }
+
+    private void updateRingerMode() {
+        final int ringerMode = Settings.Global.getInt(getContext().getContentResolver(),
+                Settings.Global.MODE_RINGER, -1);
+        final boolean nonSilentRingerMode = ringerMode == AudioManager.RINGER_MODE_NORMAL
+                || ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+        if (mZenMode == Settings.Global.ZEN_MODE_FULL && nonSilentRingerMode) {
+            Settings.Global.putInt(getContext().getContentResolver(),
+                    Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+        }
+    }
+
+    private void updateZenMode() {
+        mZenMode = Settings.Global.getInt(getContext().getContentResolver(),
+                Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+        if (DBG) Slog.d(TAG, "updateZenMode " + Settings.Global.zenModeToString(mZenMode));
+        if (mAudioManager != null) {
+            if (mZenMode == Settings.Global.ZEN_MODE_FULL) {
+                // calls vibrate if ringer mode = vibrate, so set the ringer mode as well
+                mPreZenRingerMode = mAudioManager.getRingerMode();
+                if (DBG) Slog.d(TAG, "Muting calls mPreZenRingerMode=" + mPreZenRingerMode);
+                mAudioManager.setStreamMute(AudioManager.STREAM_RING, true);
+                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
+                // alarms don't simply respect mute, so set the volume as well
+                mPreZenAlarmVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM);
+                if (DBG) Slog.d(TAG, "Muting alarms mPreZenAlarmVolume=" + mPreZenAlarmVolume);
+                mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, true);
+                mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0);
+            } else {
+                if (DBG) Slog.d(TAG, "Unmuting calls");
+                mAudioManager.setStreamMute(AudioManager.STREAM_RING, false);
+                if (mPreZenRingerMode != -1) {
+                    if (DBG) Slog.d(TAG, "Restoring ringer mode to " + mPreZenRingerMode);
+                    mAudioManager.setRingerMode(mPreZenRingerMode);
+                    mPreZenRingerMode = -1;
+                }
+                if (DBG) Slog.d(TAG, "Unmuting alarms");
+                mAudioManager.setStreamMute(AudioManager.STREAM_ALARM, false);
+                if (mPreZenAlarmVolume != -1) {
+                    if (DBG) Slog.d(TAG, "Restoring STREAM_ALARM to " + mPreZenAlarmVolume);
+                    mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, mPreZenAlarmVolume, 0);
+                    mPreZenAlarmVolume = -1;
+                }
+            }
+        }
+    }
+
+    private boolean isCall(String pkg, Notification n) {
+        return CALL_PACKAGES.contains(pkg);
+    }
+
+    private boolean isAlarm(String pkg, Notification n) {
+        return ALARM_PACKAGES.contains(pkg);
+    }
+
+    private boolean shouldIntercept(String pkg, Notification n) {
+        if (mZenMode == Settings.Global.ZEN_MODE_LIMITED) {
+            return !isCall(pkg, n) && !isAlarm(pkg, n);
+        } else if (mZenMode == Settings.Global.ZEN_MODE_FULL) {
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 07a74cd..7f00ce7 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3774,6 +3774,7 @@
             updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
             if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
         }
+        boolean updatedPkgBetter = false;
         // First check if this is a system package that may involve an update
         if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
             if (ps != null && !ps.codePath.equals(scanFile)) {
@@ -3828,6 +3829,7 @@
                     synchronized (mPackages) {
                         mSettings.enableSystemPackageLPw(ps.name);
                     }
+                    updatedPkgBetter = true;
                 }
             }
         }
@@ -3904,7 +3906,7 @@
 
         String codePath = null;
         String resPath = null;
-        if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) {
+        if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
             if (ps != null && ps.resourcePathString != null) {
                 resPath = ps.resourcePathString;
             } else {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 38a1949..fc98c4e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -984,27 +984,26 @@
             Slog.w(LOG_TAG, "Only user owner can have related users");
             return null;
         }
-        synchronized (mPackagesLock) {
-            UserInfo relatedUser = getUserInfoLocked(relatedUserId);
-            if (relatedUser == null) {
-                return null;
-            }
-            return createUserInternal(name, flags, relatedUser);
-        }
+        return createUserInternal(name, flags, relatedUserId);
     }
 
     @Override
     public UserInfo createUser(String name, int flags) {
         checkManageUsersPermission("Only the system can create users");
-        return createUserInternal(name, flags, null);
+        return createUserInternal(name, flags, UserHandle.USER_NULL);
     }
 
-    private UserInfo createUserInternal(String name, int flags, UserInfo relatedUser) {
+    private UserInfo createUserInternal(String name, int flags, int relatedUserId) {
         final long ident = Binder.clearCallingIdentity();
-        final UserInfo userInfo;
+        UserInfo userInfo = null;
         try {
             synchronized (mInstallLock) {
                 synchronized (mPackagesLock) {
+                    UserInfo relatedUser = null;
+                    if (relatedUserId != UserHandle.USER_NULL) {
+                        relatedUser = getUserInfoLocked(relatedUserId);
+                        if (relatedUser == null) return null;
+                    }
                     if (isUserLimitReachedLocked()) return null;
                     int userId = getNextAvailableIdLocked();
                     userInfo = new UserInfo(userId, name, null, flags);
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 09be3a8..e1ccf46 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -130,7 +130,7 @@
      * Called when a wake lock is acquired.
      */
     public void onWakeLockAcquired(int flags, String tag, String packageName,
-            int ownerUid, int ownerPid, WorkSource workSource) {
+            int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
         if (DEBUG) {
             Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
                     + "\", packageName=" + packageName
@@ -143,11 +143,11 @@
             boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0
                     && ownerUid == Process.SYSTEM_UID;
             if (workSource != null) {
-                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType,
-                        unimportantForLogging);
+                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, historyTag,
+                        monitorType, unimportantForLogging);
             } else {
-                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType,
-                        unimportantForLogging);
+                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
+                        monitorType, unimportantForLogging);
                 // XXX need to deal with disabled operations.
                 mAppOps.startOperation(AppOpsManager.getToken(mAppOps),
                         AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f420988..e7bbf1c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -632,7 +632,7 @@
     }
 
     private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
-            WorkSource ws, int uid, int pid) {
+            WorkSource ws, String historyTag, int uid, int pid) {
         synchronized (mLock) {
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "acquireWakeLockInternal: lock=" + Objects.hashCode(lock)
@@ -647,11 +647,11 @@
                 if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
                     // Update existing wake lock.  This shouldn't happen but is harmless.
                     notifyWakeLockReleasedLocked(wakeLock);
-                    wakeLock.updateProperties(flags, tag, packageName, ws, uid, pid);
+                    wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid);
                     notifyWakeLockAcquiredLocked(wakeLock);
                 }
             } else {
-                wakeLock = new WakeLock(lock, flags, tag, packageName, ws, uid, pid);
+                wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid);
                 try {
                     lock.linkToDeath(wakeLock, 0);
                 } catch (RemoteException ex) {
@@ -786,7 +786,8 @@
         if (mSystemReady) {
             wakeLock.mNotifiedAcquired = true;
             mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName,
-                    wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource);
+                    wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource,
+                    wakeLock.mHistoryTag);
         }
     }
 
@@ -1590,12 +1591,9 @@
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
                 | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
             final int newScreenState = getDesiredScreenPowerStateLocked();
-            if (newScreenState != mDisplayPowerRequest.screenState) {
-                mDisplayPowerRequest.screenState = newScreenState;
-                nativeSetPowerState(
-                        mDisplayPowerRequest.wantScreenOnNormal(),
-                        newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
-            }
+            mDisplayPowerRequest.screenState = newScreenState;
+            nativeSetPowerState(isScreenOnLocked(),
+                    newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
 
             int screenBrightness = mScreenBrightnessSettingDefault;
             float screenAutoBrightnessAdjustment = 0.0f;
@@ -1805,11 +1803,15 @@
 
     private boolean isScreenOnInternal() {
         synchronized (mLock) {
-            return !mSystemReady
-                    || mDisplayPowerRequest.wantScreenOnNormal();
+            return isScreenOnLocked();
         }
     }
 
+    private boolean isScreenOnLocked() {
+        return mWakefulness == WAKEFULNESS_AWAKE
+                || mWakefulness == WAKEFULNESS_DREAMING;
+    }
+
     private void handleBatteryStateChangedLocked() {
         mDirty |= DIRTY_BATTERY_STATE;
         updatePowerStateLocked();
@@ -2274,17 +2276,19 @@
         public String mTag;
         public final String mPackageName;
         public WorkSource mWorkSource;
+        public String mHistoryTag;
         public final int mOwnerUid;
         public final int mOwnerPid;
         public boolean mNotifiedAcquired;
 
         public WakeLock(IBinder lock, int flags, String tag, String packageName,
-                WorkSource workSource, int ownerUid, int ownerPid) {
+                WorkSource workSource, String historyTag, int ownerUid, int ownerPid) {
             mLock = lock;
             mFlags = flags;
             mTag = tag;
             mPackageName = packageName;
             mWorkSource = copyWorkSource(workSource);
+            mHistoryTag = historyTag;
             mOwnerUid = ownerUid;
             mOwnerPid = ownerPid;
         }
@@ -2304,7 +2308,7 @@
         }
 
         public void updateProperties(int flags, String tag, String packageName,
-                WorkSource workSource, int ownerUid, int ownerPid) {
+                WorkSource workSource, String historyTag, int ownerUid, int ownerPid) {
             if (!mPackageName.equals(packageName)) {
                 throw new IllegalStateException("Existing wake lock package name changed: "
                         + mPackageName + " to " + packageName);
@@ -2320,6 +2324,7 @@
             mFlags = flags;
             mTag = tag;
             updateWorkSource(workSource);
+            mHistoryTag = historyTag;
         }
 
         public boolean hasSameWorkSource(WorkSource workSource) {
@@ -2517,12 +2522,12 @@
         @Override // Binder call
         public void acquireWakeLockWithUid(IBinder lock, int flags, String tag,
                 String packageName, int uid) {
-            acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid));
+            acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid), null);
         }
 
         @Override // Binder call
         public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
-                WorkSource ws) {
+                WorkSource ws, String historyTag) {
             if (lock == null) {
                 throw new IllegalArgumentException("lock must not be null");
             }
@@ -2543,7 +2548,7 @@
             final int pid = Binder.getCallingPid();
             final long ident = Binder.clearCallingIdentity();
             try {
-                acquireWakeLockInternal(lock, flags, tag, packageName, ws, uid, pid);
+                acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 2ae467e..8219eb5 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -23,9 +23,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.util.Slog;
@@ -207,6 +205,10 @@
 
     @Override
     public void disable(int what, IBinder token, String pkg) {
+        if (!mNotificationDelegate.allowDisable(what, token, pkg)) {
+            if (SPEW) Slog.d(TAG, "Blocking disable request from " + pkg);
+            return;
+        }
         disableInternal(mCurrentUserId, what, token, pkg);
     }
 
@@ -676,26 +678,4 @@
             }
         }
     }
-
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
-                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                collapsePanels();
-            }
-            /*
-            else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
-                updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
-                        intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
-                        intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
-                        intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
-            }
-            else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                updateResources();
-            }
-            */
-        }
-    };
-
 }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 93f6d22..0b19b5c 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -669,10 +669,15 @@
 
             int flags = SurfaceControl.HIDDEN;
             final WindowManager.LayoutParams attrs = mWin.mAttrs;
+            final boolean isVideoPlane =
+                    (attrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_VIDEO_PLANE) != 0;
 
             if ((attrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
                 flags |= SurfaceControl.SECURE;
             }
+            if (isVideoPlane) {
+                flags |= SurfaceControl.FX_SURFACE_VIDEO_PLANE;
+            }
             if (DEBUG_VISIBILITY) Slog.v(
                 TAG, "Creating surface in session "
                 + mSession.mSurfaceSession + " window " + this
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 7675ba6..56144b0 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -30,7 +30,6 @@
     frameworks/base/libs \
     frameworks/base/core/jni \
     frameworks/native/services \
-    external/skia/include/core \
     libcore/include \
     libcore/include/libsuspend \
 	$(call include-path-for, libhardware)/hardware \
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index fc6de60..bc866d3 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -41,7 +41,11 @@
     jmethodID mConstructor;
 } gParcelFileDescriptorOffsets;
 
-static jmethodID method_usbDeviceAdded;
+static jmethodID method_beginUsbDeviceAdded;
+static jmethodID method_addUsbConfiguration;
+static jmethodID method_addUsbInterface;
+static jmethodID method_addUsbEndpoint;
+static jmethodID method_endUsbDeviceAdded;
 static jmethodID method_usbDeviceRemoved;
 
 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
@@ -68,64 +72,69 @@
     Vector<int> endpointValues;
     const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device);
 
-    uint16_t vendorId = usb_device_get_vendor_id(device);
-    uint16_t productId = usb_device_get_product_id(device);
-    uint8_t deviceClass = deviceDesc->bDeviceClass;
-    uint8_t deviceSubClass = deviceDesc->bDeviceSubClass;
-    uint8_t protocol = deviceDesc->bDeviceProtocol;
     char *manufacturer = usb_device_get_manufacturer_name(device);
     char *product = usb_device_get_product_name(device);
     char *serial = usb_device_get_serial(device);
 
-    usb_descriptor_iter_init(device, &iter);
-
-    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
-        if (desc->bDescriptorType == USB_DT_INTERFACE) {
-            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
-
-            // push class, subclass, protocol and number of endpoints into interfaceValues vector
-            interfaceValues.add(interface->bInterfaceNumber);
-            interfaceValues.add(interface->bInterfaceClass);
-            interfaceValues.add(interface->bInterfaceSubClass);
-            interfaceValues.add(interface->bInterfaceProtocol);
-            interfaceValues.add(interface->bNumEndpoints);
-        } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
-            struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc;
-
-            // push address, attributes, max packet size and interval into endpointValues vector
-            endpointValues.add(endpoint->bEndpointAddress);
-            endpointValues.add(endpoint->bmAttributes);
-            endpointValues.add(__le16_to_cpu(endpoint->wMaxPacketSize));
-            endpointValues.add(endpoint->bInterval);
-        }
-    }
-
-    usb_device_close(device);
-
-    // handle generic device notification
-    int length = interfaceValues.size();
-    jintArray interfaceArray = env->NewIntArray(length);
-    env->SetIntArrayRegion(interfaceArray, 0, length, interfaceValues.array());
-
-    length = endpointValues.size();
-    jintArray endpointArray = env->NewIntArray(length);
-    env->SetIntArrayRegion(endpointArray, 0, length, endpointValues.array());
-
     jstring deviceName = env->NewStringUTF(devname);
     jstring manufacturerName = env->NewStringUTF(manufacturer);
     jstring productName = env->NewStringUTF(product);
     jstring serialNumber = env->NewStringUTF(serial);
-    env->CallVoidMethod(thiz, method_usbDeviceAdded,
-            deviceName, vendorId, productId, deviceClass,
-            deviceSubClass, protocol, manufacturerName,
-            productName, serialNumber, interfaceArray, endpointArray);
 
-    env->DeleteLocalRef(interfaceArray);
-    env->DeleteLocalRef(endpointArray);
+    jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded,
+            deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device),
+            deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol,
+            manufacturerName, productName, serialNumber);
+
     env->DeleteLocalRef(serialNumber);
     env->DeleteLocalRef(productName);
     env->DeleteLocalRef(manufacturerName);
     env->DeleteLocalRef(deviceName);
+    free(manufacturer);
+    free(product);
+    free(serial);
+
+    if (!result) goto fail;
+
+    usb_descriptor_iter_init(device, &iter);
+
+    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
+        if (desc->bDescriptorType == USB_DT_CONFIG) {
+            struct usb_config_descriptor *config = (struct usb_config_descriptor *)desc;
+            char *name = usb_device_get_string(device, config->iConfiguration);
+            jstring configName = env->NewStringUTF(name);
+
+            env->CallVoidMethod(thiz, method_addUsbConfiguration,
+                    config->bConfigurationValue, configName, config->bmAttributes,
+                    config->bMaxPower);
+
+            env->DeleteLocalRef(configName);
+            free(name);
+        } else if (desc->bDescriptorType == USB_DT_INTERFACE) {
+            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
+            char *name = usb_device_get_string(device, interface->iInterface);
+            jstring interfaceName = env->NewStringUTF(name);
+
+            env->CallVoidMethod(thiz, method_addUsbInterface,
+                    interface->bInterfaceNumber, interfaceName, interface->bAlternateSetting,
+                    interface->bInterfaceClass, interface->bInterfaceSubClass,
+                    interface->bInterfaceProtocol);
+
+            env->DeleteLocalRef(interfaceName);
+            free(name);
+        } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
+            struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc;
+
+            env->CallVoidMethod(thiz, method_addUsbEndpoint,
+                    endpoint->bEndpointAddress, endpoint->bmAttributes,
+                    __le16_to_cpu(endpoint->wMaxPacketSize), endpoint->bInterval);
+        }
+    }
+
+    env->CallVoidMethod(thiz, method_endUsbDeviceAdded);
+
+fail:
+    usb_device_close(device);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 
     return 0;
@@ -191,12 +200,36 @@
         ALOGE("Can't find com/android/server/usb/UsbHostManager");
         return -1;
     }
-    method_usbDeviceAdded = env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I)V");
-    if (method_usbDeviceAdded == NULL) {
-        ALOGE("Can't find usbDeviceAdded");
+    method_beginUsbDeviceAdded = env->GetMethodID(clazz, "beginUsbDeviceAdded",
+            "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
+    if (method_beginUsbDeviceAdded == NULL) {
+        ALOGE("Can't find beginUsbDeviceAdded");
         return -1;
     }
-    method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved", "(Ljava/lang/String;)V");
+    method_addUsbConfiguration = env->GetMethodID(clazz, "addUsbConfiguration",
+            "(ILjava/lang/String;II)V");
+    if (method_addUsbConfiguration == NULL) {
+        ALOGE("Can't find addUsbConfiguration");
+        return -1;
+    }
+    method_addUsbInterface = env->GetMethodID(clazz, "addUsbInterface",
+            "(ILjava/lang/String;IIII)V");
+    if (method_addUsbInterface == NULL) {
+        ALOGE("Can't find addUsbInterface");
+        return -1;
+    }
+    method_addUsbEndpoint = env->GetMethodID(clazz, "addUsbEndpoint", "(IIII)V");
+    if (method_addUsbEndpoint == NULL) {
+        ALOGE("Can't find addUsbEndpoint");
+        return -1;
+    }
+    method_endUsbDeviceAdded = env->GetMethodID(clazz, "endUsbDeviceAdded", "()V");
+    if (method_endUsbDeviceAdded == NULL) {
+        ALOGE("Can't find endUsbDeviceAdded");
+        return -1;
+    }
+    method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved",
+            "(Ljava/lang/String;)V");
     if (method_usbDeviceRemoved == NULL) {
         ALOGE("Can't find usbDeviceRemoved");
         return -1;
@@ -205,7 +238,8 @@
     clazz = env->FindClass("android/os/ParcelFileDescriptor");
     LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
     gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
+    gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>",
+            "(Ljava/io/FileDescriptor;)V");
     LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
                  "Unable to find constructor for android.os.ParcelFileDescriptor");
 
diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
index ab8c959..bf34a74 100644
--- a/services/core/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp
@@ -302,15 +302,6 @@
     return ifr4.ifr_flags;
 }
 
-static int bind_to_interface(int socket, const char *name)
-{
-    if (setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) {
-        ALOGE("Cannot bind socket to %s: %s", name, strerror(errno));
-        return SYSTEM_ERROR;
-    }
-    return 0;
-}
-
 //------------------------------------------------------------------------------
 
 static void throwException(JNIEnv *env, int error, const char *message)
@@ -433,19 +424,6 @@
     return flags;
 }
 
-static void protect(JNIEnv *env, jobject thiz, jint socket, jstring jName)
-{
-    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
-    if (!name) {
-        jniThrowNullPointerException(env, "name");
-        return;
-    }
-    if (bind_to_interface(socket, name) < 0) {
-        throwException(env, SYSTEM_ERROR, "Cannot protect socket");
-    }
-    env->ReleaseStringUTFChars(jName, name);
-}
-
 //------------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
@@ -455,7 +433,6 @@
     {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
     {"jniReset", "(Ljava/lang/String;)V", (void *)reset},
     {"jniCheck", "(Ljava/lang/String;)I", (void *)check},
-    {"jniProtect", "(ILjava/lang/String;)V", (void *)protect},
 };
 
 int register_android_server_connectivity_Vpn(JNIEnv *env)
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index dfaad0b..7ae5460 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -17,6 +17,7 @@
 package com.android.server.usb;
 
 import android.content.Context;
+import android.hardware.usb.UsbConfiguration;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbEndpoint;
@@ -30,6 +31,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
 
 /**
@@ -48,6 +50,13 @@
     private final Context mContext;
     private final Object mLock = new Object();
 
+    private UsbDevice mNewDevice;
+    private UsbConfiguration mNewConfiguration;
+    private UsbInterface mNewInterface;
+    private ArrayList<UsbConfiguration> mNewConfigurations;
+    private ArrayList<UsbInterface> mNewInterfaces;
+    private ArrayList<UsbEndpoint> mNewEndpoints;
+
     @GuardedBy("mLock")
     private UsbSettingsManager mCurrentSettings;
 
@@ -93,69 +102,103 @@
         return false;
     }
 
-    /* Called from JNI in monitorUsbHostBus() to report new USB devices */
-    private void usbDeviceAdded(String deviceName, int vendorID, int productID,
+    /* Called from JNI in monitorUsbHostBus() to report new USB devices
+       Returns true if successful, in which case the JNI code will continue adding configurations,
+       interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
+       have been processed
+     */
+    private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
             int deviceClass, int deviceSubclass, int deviceProtocol,
-            String manufacturerName, String productName, String serialNumber,
-            /* array of quintuples containing id, class, subclass, protocol
-               and number of endpoints for each interface */
-            int[] interfaceValues,
-           /* array of quadruples containing address, attributes, max packet size
-              and interval for each endpoint */
-            int[] endpointValues) {
+            String manufacturerName, String productName, String serialNumber) {
 
         if (isBlackListed(deviceName) ||
                 isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
-            return;
+            return false;
         }
 
         synchronized (mLock) {
             if (mDevices.get(deviceName) != null) {
                 Slog.w(TAG, "device already on mDevices list: " + deviceName);
-                return;
+                return false;
             }
 
-            int numInterfaces = interfaceValues.length / 5;
-            Parcelable[] interfaces = new UsbInterface[numInterfaces];
-            try {
-                // repackage interfaceValues as an array of UsbInterface
-                int intf, endp, ival = 0, eval = 0;
-                for (intf = 0; intf < numInterfaces; intf++) {
-                    int interfaceId = interfaceValues[ival++];
-                    int interfaceClass = interfaceValues[ival++];
-                    int interfaceSubclass = interfaceValues[ival++];
-                    int interfaceProtocol = interfaceValues[ival++];
-                    int numEndpoints = interfaceValues[ival++];
-
-                    Parcelable[] endpoints = new UsbEndpoint[numEndpoints];
-                    for (endp = 0; endp < numEndpoints; endp++) {
-                        int address = endpointValues[eval++];
-                        int attributes = endpointValues[eval++];
-                        int maxPacketSize = endpointValues[eval++];
-                        int interval = endpointValues[eval++];
-                        endpoints[endp] = new UsbEndpoint(address, attributes,
-                                maxPacketSize, interval);
-                    }
-
-                    // don't allow if any interfaces are blacklisted
-                    if (isBlackListed(interfaceClass, interfaceSubclass, interfaceProtocol)) {
-                        return;
-                    }
-                    interfaces[intf] = new UsbInterface(interfaceId, interfaceClass,
-                            interfaceSubclass, interfaceProtocol, endpoints);
-                }
-            } catch (Exception e) {
-                // beware of index out of bound exceptions, which might happen if
-                // a device does not set bNumEndpoints correctly
-                Slog.e(TAG, "error parsing USB descriptors", e);
-                return;
+            if (mNewDevice != null) {
+                Slog.e(TAG, "mNewDevice is not null in endUsbDeviceAdded");
+                return false;
             }
 
-            UsbDevice device = new UsbDevice(deviceName, vendorID, productID,
+            mNewDevice = new UsbDevice(deviceName, vendorID, productID,
                     deviceClass, deviceSubclass, deviceProtocol,
-                    manufacturerName, productName, serialNumber, interfaces);
-            mDevices.put(deviceName, device);
-            getCurrentSettings().deviceAttached(device);
+                    manufacturerName, productName, serialNumber);
+
+            mNewConfigurations = new ArrayList<UsbConfiguration>();
+            mNewInterfaces = new ArrayList<UsbInterface>();
+            mNewEndpoints = new ArrayList<UsbEndpoint>();
+        }
+        return true;
+    }
+
+    /* Called from JNI in monitorUsbHostBus() to report new USB configuration for the device
+       currently being added.  Returns true if successful, false in case of error.
+     */
+    private void addUsbConfiguration(int id, String name, int attributes, int maxPower) {
+        if (mNewConfiguration != null) {
+            mNewConfiguration.setInterfaces(
+                    mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
+            mNewInterfaces.clear();
+        }
+
+        mNewConfiguration = new UsbConfiguration(id, name, attributes, maxPower);
+        mNewConfigurations.add(mNewConfiguration);
+    }
+
+    /* Called from JNI in monitorUsbHostBus() to report new USB interface for the device
+       currently being added.  Returns true if successful, false in case of error.
+     */
+    private void addUsbInterface(int id, String name, int altSetting,
+            int Class, int subClass, int protocol) {
+        if (mNewInterface != null) {
+            mNewInterface.setEndpoints(
+                    mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
+            mNewEndpoints.clear();
+        }
+
+        mNewInterface = new UsbInterface(id, altSetting, name, Class, subClass, protocol);
+        mNewInterfaces.add(mNewInterface);
+    }
+
+    /* Called from JNI in monitorUsbHostBus() to report new USB endpoint for the device
+       currently being added.  Returns true if successful, false in case of error.
+     */
+    private void addUsbEndpoint(int address, int attributes, int maxPacketSize, int interval) {
+        mNewEndpoints.add(new UsbEndpoint(address, attributes, maxPacketSize, interval));
+    }
+
+    /* Called from JNI in monitorUsbHostBus() to finish adding a new device */
+    private void endUsbDeviceAdded() {
+        if (mNewInterface != null) {
+            mNewInterface.setEndpoints(
+                    mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
+        }
+        if (mNewConfiguration != null) {
+            mNewConfiguration.setInterfaces(
+                    mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
+        }
+
+        synchronized (mLock) {
+            if (mNewDevice != null) {
+                mNewDevice.setConfigurations(
+                        mNewConfigurations.toArray(new UsbConfiguration[mNewConfigurations.size()]));
+                mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
+                Slog.d(TAG, "Added device " + mNewDevice);
+                getCurrentSettings().deviceAttached(mNewDevice);
+            } else {
+                Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
+            }
+            mNewDevice = null;
+            mNewConfigurations = null;
+            mNewInterfaces = null;
+            mNewEndpoints = null;
         }
     }
 
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
index 9bc3baa..2b14384 100644
--- a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
@@ -12,10 +12,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- 
+
 package com.android.onemedia;
 
-import android.media.MediaSessionToken;
+import android.media.session.MediaSessionToken;
 
 interface IPlayerCallback {
     void onSessionChanged(in MediaSessionToken session);
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
index ab1d3fc..efdbe9a 100644
--- a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
@@ -12,17 +12,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- 
+
 package com.android.onemedia;
 
-import android.media.MediaSessionToken;
+import android.media.session.MediaSessionToken;
 import android.os.Bundle;
 
 import com.android.onemedia.IPlayerCallback;
 import com.android.onemedia.playback.IRequestCallback;
 
 interface IPlayerService {
-    MediaSessionToken getSessionToken(); 
+    MediaSessionToken getSessionToken();
     void registerCallback(in IPlayerCallback cb);
     void unregisterCallback(in IPlayerCallback cb);
     void sendRequest(String action, in Bundle params, in IRequestCallback cb);
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
index 4ccc846..3f15db5 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
@@ -1,8 +1,8 @@
 
 package com.android.onemedia;
 
-import android.media.MediaController;
-import android.media.MediaSessionManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
index 0819077..0b2ba8f 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerService.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
@@ -2,7 +2,7 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.media.MediaSessionToken;
+import android.media.session.MediaSessionToken;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 25a8f0d..e5fb0d0 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -2,9 +2,9 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.media.MediaSession;
-import android.media.MediaSessionManager;
-import android.media.MediaSessionToken;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionToken;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.KeyEvent;
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index cbeaae8..49b8b55 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -59,10 +59,10 @@
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
           mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
           mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
-          mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL), mExtraPackages(NULL),
-          mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false), mProduct(NULL),
-          mUseCrunchCache(false), mErrorOnFailedInsert(false), mErrorOnMissingConfigEntry(false),
-          mOutputTextSymbols(NULL),
+          mVersionCode(NULL), mVersionName(NULL), mReplaceVersion(false), mCustomPackage(NULL),
+          mExtraPackages(NULL), mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false),
+          mProduct(NULL), mUseCrunchCache(false), mErrorOnFailedInsert(false),
+          mErrorOnMissingConfigEntry(false), mOutputTextSymbols(NULL),
           mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
           mArgc(0), mArgv(NULL)
         {}
@@ -166,6 +166,8 @@
     void setVersionCode(const char*  val) { mVersionCode = val; }
     const char* getVersionName() const { return mVersionName; }
     void setVersionName(const char* val) { mVersionName = val; }
+    bool getReplaceVersion() { return mReplaceVersion; }
+    void setReplaceVersion(bool val) { mReplaceVersion = val; }
     const char* getCustomPackage() const { return mCustomPackage; }
     void setCustomPackage(const char* val) { mCustomPackage = val; }
     const char* getExtraPackages() const { return mExtraPackages; }
@@ -285,6 +287,7 @@
     const char* mMaxSdkVersion;
     const char* mVersionCode;
     const char* mVersionName;
+    bool        mReplaceVersion;
     const char* mCustomPackage;
     const char* mExtraPackages;
     const char* mMaxResVersion;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 1ed4630..33711fa 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -153,6 +153,11 @@
         "       inserts android:versionCode in to manifest.\n"
         "   --version-name\n"
         "       inserts android:versionName in to manifest.\n"
+        "   --replace-version\n"
+        "       If --version-code and/or --version-name are specified, these\n"
+        "       values will replace any value already in the manifest. By\n"
+        "       default, nothing is changed if the manifest already defines\n"
+        "       these attributes.\n"
         "   --custom-package\n"
         "       generates R.java into a different package.\n"
         "   --extra-packages\n"
@@ -532,6 +537,8 @@
                         goto bail;
                     }
                     bundle.setVersionName(argv[0]);
+                } else if (strcmp(cp, "-replace-version") == 0) {
+                    bundle.setReplaceVersion(true);
                 } else if (strcmp(cp, "-values") == 0) {
                     bundle.setValues(true);
                 } else if (strcmp(cp, "-include-meta-data") == 0) {
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index c923bc2..6d9d62e 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -676,13 +676,15 @@
 }
 
 /*
- * Inserts an attribute in a given node, only if the attribute does not
- * exist.
+ * Inserts an attribute in a given node.
  * If errorOnFailedInsert is true, and the attribute already exists, returns false.
- * Returns true otherwise, even if the attribute already exists.
+ * If replaceExisting is true, the attribute will be updated if it already exists.
+ * Returns true otherwise, even if the attribute already exists, and does not modify
+ * the existing attribute's value.
  */
 bool addTagAttribute(const sp<XMLNode>& node, const char* ns8,
-        const char* attr8, const char* value, bool errorOnFailedInsert)
+        const char* attr8, const char* value, bool errorOnFailedInsert,
+        bool replaceExisting)
 {
     if (value == NULL) {
         return true;
@@ -691,7 +693,16 @@
     const String16 ns(ns8);
     const String16 attr(attr8);
 
-    if (node->getAttribute(ns, attr) != NULL) {
+    XMLNode::attribute_entry* existingEntry = node->editAttribute(ns, attr);
+    if (existingEntry != NULL) {
+        if (replaceExisting) {
+            NOISY(printf("Info: AndroidManifest.xml already defines %s (in %s);"
+                         " overwriting existing value from manifest.\n",
+                         String8(attr).string(), String8(ns).string()));
+            existingEntry->string = String16(value);
+            return true;
+        }
+
         if (errorOnFailedInsert) {
             fprintf(stderr, "Error: AndroidManifest.xml already defines %s (in %s);"
                             " cannot insert new value %s.\n",
@@ -711,6 +722,18 @@
     return true;
 }
 
+/*
+ * Inserts an attribute in a given node, only if the attribute does not
+ * exist.
+ * If errorOnFailedInsert is true, and the attribute already exists, returns false.
+ * Returns true otherwise, even if the attribute already exists.
+ */
+bool addTagAttribute(const sp<XMLNode>& node, const char* ns8,
+        const char* attr8, const char* value, bool errorOnFailedInsert)
+{
+    return addTagAttribute(node, ns8, attr8, value, errorOnFailedInsert, false);
+}
+
 static void fullyQualifyClassName(const String8& package, sp<XMLNode> node,
         const String16& attrName) {
     XMLNode::attribute_entry* attr = node->editAttribute(
@@ -748,13 +771,14 @@
     }
 
     bool errorOnFailedInsert = bundle->getErrorOnFailedInsert();
+    bool replaceVersion = bundle->getReplaceVersion();
 
     if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode",
-            bundle->getVersionCode(), errorOnFailedInsert)) {
+            bundle->getVersionCode(), errorOnFailedInsert, replaceVersion)) {
         return UNKNOWN_ERROR;
     }
     if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
-            bundle->getVersionName(), errorOnFailedInsert)) {
+            bundle->getVersionName(), errorOnFailedInsert, replaceVersion)) {
         return UNKNOWN_ERROR;
     }
     
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath
index 2e4274d..aef3efa 100644
--- a/tools/layoutlib/bridge/.classpath
+++ b/tools/layoutlib/bridge/.classpath
@@ -1,12 +1,14 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry excluding="org/kxml2/io/" kind="src" path="src"/>
+	<classpathentry kind="src" path="tests/src"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
+	<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/layoutlib_api/layoutlib_api-prebuilt.jar" sourcepath="/ANDROID_SRC/tools/base/layoutlib-api/src/main"/>
 	<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
 	<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
 	<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar"/>
 	<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/>
 	<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/icu4j/icu4j.jar"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
index fd594f7..5f0d98b 100644
--- a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
@@ -33,11 +33,6 @@
     private static long sBootTime = System.currentTimeMillis();
     private static long sBootTimeNano = System.nanoTime();
 
-    @LayoutlibDelegate
-    /*package*/ static boolean setCurrentTimeMillis(long millis) {
-        return true;
-    }
-
     /**
      * Returns milliseconds since boot, not counting time spent in deep sleep.
      * <b>Note:</b> This value may get reset occasionally (before it would
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 281337c..a90632c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -39,7 +39,7 @@
     }
 
     @Override
-    public void acquireWakeLock(IBinder arg0, int arg1, String arg2, String arg2_5, WorkSource arg3)
+    public void acquireWakeLock(IBinder arg0, int arg1, String arg2, String arg2_5, WorkSource arg3, String arg4)
             throws RemoteException {
         // pass for now.
     }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index a79fba1..2ef3d5f 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -114,6 +114,7 @@
                         "android.os.*",  // for android.os.Handler
                         "android.database.ContentObserver", // for Digital clock
                         "com.android.i18n.phonenumbers.*",  // for TextView with autolink attribute
+                        "android.app.DatePickerDialog",     // b.android.com/28318
                     },
                     excludeClasses,
                     new String[] {
diff --git a/tools/preload/Android.mk b/tools/preload/Android.mk
index f325870..14a4547 100644
--- a/tools/preload/Android.mk
+++ b/tools/preload/Android.mk
@@ -20,4 +20,4 @@
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
-include $(call all-subdir-makefiles)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 4a6b1ff..84e933d 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -20,6 +20,8 @@
 import android.net.wifi.BatchedScanSettings;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
+import android.net.wifi.ScanSettings;
+import android.net.wifi.WifiChannel;
 import android.net.wifi.ScanResult;
 import android.net.DhcpInfo;
 
@@ -45,7 +47,9 @@
 
     boolean pingSupplicant();
 
-    void startScan(in WorkSource ws);
+    List<WifiChannel> getChannelList();
+
+    void startScan(in ScanSettings requested, in WorkSource ws);
 
     List<ScanResult> getScanResults(String callingPackage);
 
diff --git a/wifi/java/android/net/wifi/ScanSettings.aidl b/wifi/java/android/net/wifi/ScanSettings.aidl
new file mode 100644
index 0000000..ebd2a39
--- /dev/null
+++ b/wifi/java/android/net/wifi/ScanSettings.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.net.wifi;
+
+parcelable ScanSettings;
diff --git a/wifi/java/android/net/wifi/ScanSettings.java b/wifi/java/android/net/wifi/ScanSettings.java
new file mode 100644
index 0000000..094ce34
--- /dev/null
+++ b/wifi/java/android/net/wifi/ScanSettings.java
@@ -0,0 +1,87 @@
+/*
+ * 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.net.wifi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Bundle of customized scan settings
+ *
+ * @see WifiManager#startCustomizedScan
+ *
+ * @hide
+ */
+public class ScanSettings implements Parcelable {
+
+    /** channel set to scan. this can be null or empty, indicating a full scan */
+    public Collection<WifiChannel> channelSet;
+
+    /** public constructor */
+    public ScanSettings() { }
+
+    /** copy constructor */
+    public ScanSettings(ScanSettings source) {
+        if (source.channelSet != null)
+            channelSet = new ArrayList<WifiChannel>(source.channelSet);
+    }
+
+    /** check for validity */
+    public boolean isValid() {
+        for (WifiChannel channel : channelSet)
+            if (!channel.isValid()) return false;
+        return true;
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(channelSet == null ? 0 : channelSet.size());
+        if (channelSet != null)
+            for (WifiChannel channel : channelSet) channel.writeToParcel(out, flags);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<ScanSettings> CREATOR =
+            new Parcelable.Creator<ScanSettings>() {
+        @Override
+        public ScanSettings createFromParcel(Parcel in) {
+            ScanSettings settings = new ScanSettings();
+            int size = in.readInt();
+            if (size > 0) {
+                settings.channelSet = new ArrayList<WifiChannel>(size);
+                while (size-- > 0)
+                    settings.channelSet.add(WifiChannel.CREATOR.createFromParcel(in));
+            }
+            return settings;
+        }
+
+        @Override
+        public ScanSettings[] newArray(int size) {
+            return new ScanSettings[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/WifiChannel.aidl b/wifi/java/android/net/wifi/WifiChannel.aidl
new file mode 100644
index 0000000..c3d06bd
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiChannel.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.net.wifi;
+
+parcelable WifiChannel;
diff --git a/wifi/java/android/net/wifi/WifiChannel.java b/wifi/java/android/net/wifi/WifiChannel.java
new file mode 100644
index 0000000..640481e
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiChannel.java
@@ -0,0 +1,87 @@
+/*
+ * 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.net.wifi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Wifi Channel
+ *
+ * @see ScanSettings
+ *
+ * @hide
+ */
+public class WifiChannel implements Parcelable {
+
+    private static final int MIN_FREQ_MHZ = 2412;
+    private static final int MAX_FREQ_MHZ = 5825;
+
+    private static final int MIN_CHANNEL_NUM = 1;
+    private static final int MAX_CHANNEL_NUM = 196;
+
+    /** frequency */
+    public int freqMHz;
+
+    /** channel number */
+    public int channelNum;
+
+    /** is it a DFS channel? */
+    public boolean isDFS;
+
+    /** public constructor */
+    public WifiChannel() { }
+
+    /** check for validity */
+    public boolean isValid() {
+        if (freqMHz < MIN_FREQ_MHZ || freqMHz > MAX_FREQ_MHZ) return false;
+        if (channelNum < MIN_CHANNEL_NUM || channelNum > MAX_CHANNEL_NUM) return false;
+        return true;
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** implement Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(freqMHz);
+        out.writeInt(channelNum);
+        out.writeInt(isDFS ? 1 : 0);
+    }
+
+    /** implement Parcelable interface */
+    public static final Parcelable.Creator<WifiChannel> CREATOR =
+            new Parcelable.Creator<WifiChannel>() {
+        @Override
+        public WifiChannel createFromParcel(Parcel in) {
+            WifiChannel channel = new WifiChannel();
+            channel.freqMHz = in.readInt();
+            channel.channelNum = in.readInt();
+            channel.isDFS = in.readInt() != 0;
+            return channel;
+        }
+
+        @Override
+        public WifiChannel[] newArray(int size) {
+            return new WifiChannel[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 6a13067..4a6821c 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -69,6 +69,10 @@
     public static final String LINK_SPEED_UNITS = "Mbps";
     private int mLinkSpeed;
 
+    /** Frequency in MHz */
+    public static final String FREQUENCY_UNITS = "MHz";
+    private int mFrequency;
+
     private InetAddress mIpAddress;
     private String mMacAddress;
 
@@ -86,6 +90,7 @@
         mSupplicantState = SupplicantState.UNINITIALIZED;
         mRssi = -9999;
         mLinkSpeed = -1;
+        mFrequency = -1;
     }
 
     /**
@@ -100,6 +105,7 @@
             mNetworkId = source.mNetworkId;
             mRssi = source.mRssi;
             mLinkSpeed = source.mLinkSpeed;
+            mFrequency = source.mFrequency;
             mIpAddress = source.mIpAddress;
             mMacAddress = source.mMacAddress;
             mMeteredHint = source.mMeteredHint;
@@ -179,6 +185,20 @@
     }
 
     /**
+     * Returns the current frequency in {@link #FREQUENCY_UNITS}.
+     * @return the frequency.
+     * @see #FREQUENCY_UNITS
+     */
+    public int getFrequency() {
+        return mFrequency;
+    }
+
+    /** @hide */
+    public void setFrequency(int frequency) {
+        this.mFrequency = frequency;
+    }
+
+    /**
      * Record the MAC address of the WLAN interface
      * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
      * @hide
@@ -303,7 +323,8 @@
             append(", Supplicant state: ").
             append(mSupplicantState == null ? none : mSupplicantState).
             append(", RSSI: ").append(mRssi).
-            append(", Link speed: ").append(mLinkSpeed).
+            append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
+            append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
             append(", Net ID: ").append(mNetworkId).
             append(", Metered hint: ").append(mMeteredHint);
 
@@ -320,6 +341,7 @@
         dest.writeInt(mNetworkId);
         dest.writeInt(mRssi);
         dest.writeInt(mLinkSpeed);
+        dest.writeInt(mFrequency);
         if (mIpAddress != null) {
             dest.writeByte((byte)1);
             dest.writeByteArray(mIpAddress.getAddress());
@@ -346,6 +368,7 @@
                 info.setNetworkId(in.readInt());
                 info.setRssi(in.readInt());
                 info.setLinkSpeed(in.readInt());
+                info.setFrequency(in.readInt());
                 if (in.readByte() == 1) {
                     try {
                         info.setInetAddress(InetAddress.getByAddress(in.createByteArray()));
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index aabe007..0862b7e 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -20,6 +20,8 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.net.DhcpInfo;
+import android.net.wifi.ScanSettings;
+import android.net.wifi.WifiChannel;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Handler;
@@ -763,6 +765,22 @@
     }
 
     /**
+     * Get a list of available channels for customized scan.
+     *
+     * @see {@link WifiChannel}
+     *
+     * @return the channel list, or null if not available
+     * @hide
+     */
+    public List<WifiChannel> getChannelList() {
+        try {
+            return mService.getChannelList();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Request a scan for access points. Returns immediately. The availability
      * of the results is made known later by means of an asynchronous event sent
      * on completion of the scan.
@@ -770,8 +788,7 @@
      */
     public boolean startScan() {
         try {
-            final WorkSource workSource = null;
-            mService.startScan(workSource);
+            mService.startScan(null, null);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -781,7 +798,42 @@
     /** @hide */
     public boolean startScan(WorkSource workSource) {
         try {
-            mService.startScan(workSource);
+            mService.startScan(null, workSource);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Request a scan for access points in specified channel list. Each channel is specified by its
+     * frequency in MHz, e.g. "5500" (do NOT include "DFS" even though it is). The availability of
+     * the results is made known later in the same way as {@link #startScan}.
+     *
+     * Note:
+     *
+     * 1. Customized scan is for non-connection purposes, i.e. it won't trigger a wifi connection
+     *    even though it finds some known networks.
+     *
+     * 2. Customized scan result may include access points that is not specified in the channel
+     *    list. An app will need to do frequency filtering if it wants to get pure results for the
+     *    channel list it specified.
+     *
+     * @hide
+     */
+    public boolean startCustomizedScan(ScanSettings requested) {
+        try {
+            mService.startScan(requested, null);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /** @hide */
+    public boolean startCustomizedScan(ScanSettings requested, WorkSource workSource) {
+        try {
+            mService.startScan(requested, workSource);
             return true;
         } catch (RemoteException e) {
             return false;