Merge "Fix Material styling in remaining dialogs and layouts" into lmp-mr1-dev
diff --git a/Android.mk b/Android.mk
index b77c2ed..960bf26 100644
--- a/Android.mk
+++ b/Android.mk
@@ -559,6 +559,7 @@
 	frameworks/base/core/java/android/content/pm/ProviderInfo.aidl \
 	frameworks/base/core/java/android/content/pm/PackageStats.aidl \
 	frameworks/base/core/java/android/content/pm/PermissionGroupInfo.aidl \
+	frameworks/base/core/java/android/content/pm/LabeledIntent.aidl \
 	frameworks/base/core/java/android/content/ComponentName.aidl \
 	frameworks/base/core/java/android/content/SyncStats.aidl \
 	frameworks/base/core/java/android/content/ContentValues.aidl \
diff --git a/api/current.txt b/api/current.txt
index 6eeceac..14567f2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3304,6 +3304,7 @@
     method public final android.app.Activity getParent();
     method public android.content.Intent getParentActivityIntent();
     method public android.content.SharedPreferences getPreferences(int);
+    method public android.net.Uri getReferrer();
     method public int getRequestedOrientation();
     method public int getTaskId();
     method public final java.lang.CharSequence getTitle();
@@ -7751,6 +7752,7 @@
     field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
+    field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
     field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
     field public static final java.lang.String EXTRA_REPLACEMENT_EXTRAS = "android.intent.extra.REPLACEMENT_EXTRAS";
     field public static final java.lang.String EXTRA_REPLACING = "android.intent.extra.REPLACING";
@@ -7810,6 +7812,7 @@
     field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
     field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
     field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
+    field public static final int URI_ANDROID_APP_SCHEME = 2; // 0x2
     field public static final int URI_INTENT_SCHEME = 1; // 0x1
   }
 
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bc57030..0cad17d 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -127,6 +127,7 @@
                 "       am screen-compat [on|off] <PACKAGE>\n" +
                 "       am to-uri [INTENT]\n" +
                 "       am to-intent-uri [INTENT]\n" +
+                "       am to-app-uri [INTENT]\n" +
                 "       am switch-user <USER_ID>\n" +
                 "       am start-user <USER_ID>\n" +
                 "       am stop-user <USER_ID>\n" +
@@ -229,6 +230,8 @@
                 "\n" +
                 "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
                 "\n" +
+                "am to-app-uri: print the given Intent specification as an android-app: URI.\n" +
+                "\n" +
                 "am switch-user: switch to put USER_ID in the foreground, starting\n" +
                 "  execution of that user if it is currently stopped.\n" +
                 "\n" +
@@ -270,7 +273,7 @@
                 "    [--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" +
+                "    [-n <COMPONENT>] [-p <PACKAGE>] [-f <FLAGS>]\n" +
                 "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
                 "    [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]\n" +
                 "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
@@ -337,9 +340,11 @@
         } else if (op.equals("screen-compat")) {
             runScreenCompat();
         } else if (op.equals("to-uri")) {
-            runToUri(false);
+            runToUri(0);
         } else if (op.equals("to-intent-uri")) {
-            runToUri(true);
+            runToUri(Intent.URI_INTENT_SCHEME);
+        } else if (op.equals("to-app-uri")) {
+            runToUri(Intent.URI_ANDROID_APP_SCHEME);
         } else if (op.equals("switch-user")) {
             runSwitchUser();
         } else if (op.equals("start-user")) {
@@ -502,6 +507,12 @@
                 if (intent == baseIntent) {
                     hasIntentInfo = true;
                 }
+            } else if (opt.equals("-p")) {
+                String str = nextArgRequired();
+                intent.setPackage(str);
+                if (intent == baseIntent) {
+                    hasIntentInfo = true;
+                }
             } else if (opt.equals("-f")) {
                 String str = nextArgRequired();
                 intent.setFlags(Integer.decode(str).intValue());
@@ -607,7 +618,8 @@
         } else if (arg.indexOf(':') >= 0) {
             // The argument is a URI.  Fully parse it, and use that result
             // to fill in any data not specified so far.
-            baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME);
+            baseIntent = Intent.parseUri(arg, Intent.URI_INTENT_SCHEME
+                    | Intent.URI_ANDROID_APP_SCHEME);
         } else if (arg.indexOf('/') >= 0) {
             // The argument is a component name.  Build an Intent to launch
             // it.
@@ -1549,9 +1561,9 @@
         } while (packageName != null);
     }
 
-    private void runToUri(boolean intentScheme) throws Exception {
+    private void runToUri(int flags) throws Exception {
         Intent intent = makeIntent(UserHandle.USER_CURRENT);
-        System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0));
+        System.out.println(intent.toUri(flags));
     }
 
     private class IntentReceiver extends IIntentReceiver.Stub {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4b705dd..148527f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -693,6 +693,7 @@
     /*package*/ String mEmbeddedID;
     private Application mApplication;
     /*package*/ Intent mIntent;
+    /*package*/ String mReferrer;
     private ComponentName mComponent;
     /*package*/ ActivityInfo mActivityInfo;
     /*package*/ ActivityThread mMainThread;
@@ -4448,6 +4449,39 @@
     }
 
     /**
+     * Return information about who launched this activity.  If the launching Intent
+     * contains an {@link android.content.Intent#EXTRA_REFERRER Intent.EXTRA_REFERRER},
+     * that will be returned as-is; otherwise, if known, an
+     * {@link Intent#URI_ANDROID_APP_SCHEME android-app:} referrer URI containing the
+     * package name that started the Intent will be returned.  This may return null if no
+     * referrer can be identified -- it is neither explicitly specified, nor is it known which
+     * application package was involved.
+     *
+     * <p>If called while inside the handling of {@link #onNewIntent}, this function will
+     * return the referrer that submitted that new intent to the activity.  Otherwise, it
+     * always returns the referrer of the original Intent.</p>
+     *
+     * <p>Note that this is <em>not</em> a security feature -- you can not trust the
+     * referrer information, applications can spoof it.</p>
+     */
+    @Nullable
+    public Uri getReferrer() {
+        Intent intent = getIntent();
+        Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+        if (referrer != null) {
+            return referrer;
+        }
+        String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
+        if (referrerName != null) {
+            return Uri.parse(referrerName);
+        }
+        if (mReferrer != null) {
+            return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
+        }
+        return null;
+    }
+
+    /**
      * Return the name of the package that invoked this activity.  This is who
      * the data in {@link #setResult setResult()} will be sent to.  You can
      * use this information to validate that the recipient is allowed to
@@ -5868,7 +5902,7 @@
             Application application, Intent intent, ActivityInfo info,
             CharSequence title, Activity parent, String id,
             NonConfigurationInstances lastNonConfigurationInstances,
-            Configuration config, IVoiceInteractor voiceInteractor) {
+            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
         attachBaseContext(context);
 
         mFragments.attachActivity(this, mContainer, null);
@@ -5891,6 +5925,7 @@
         mIdent = ident;
         mApplication = application;
         mIntent = intent;
+        mReferrer = referrer;
         mComponent = intent.getComponent();
         mActivityInfo = info;
         mTitle = title;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cf6c049..5f21d75 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -94,6 +94,7 @@
 import android.security.AndroidKeyStoreProvider;
 
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.RuntimeInit;
 import com.android.internal.os.SamplingProfilerIntegration;
@@ -268,6 +269,7 @@
         IBinder token;
         int ident;
         Intent intent;
+        String referrer;
         IVoiceInteractor voiceInteractor;
         Bundle state;
         PersistableBundle persistentState;
@@ -290,7 +292,7 @@
         LoadedApk packageInfo;
 
         List<ResultInfo> pendingResults;
-        List<Intent> pendingIntents;
+        List<ReferrerIntent> pendingIntents;
 
         boolean startsNotResumed;
         boolean isForward;
@@ -348,7 +350,7 @@
     }
 
     static final class NewIntentData {
-        List<Intent> intents;
+        List<ReferrerIntent> intents;
         IBinder token;
         public String toString() {
             return "NewIntentData{intents=" + intents + " token=" + token + "}";
@@ -605,9 +607,9 @@
         // activity itself back to the activity manager. (matters more with ipc)
         public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                 ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-                IVoiceInteractor voiceInteractor, int procState, Bundle state,
+                String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
                 PersistableBundle persistentState, List<ResultInfo> pendingResults,
-                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+                List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
                 ProfilerInfo profilerInfo) {
 
             updateProcessState(procState, false);
@@ -617,6 +619,7 @@
             r.token = token;
             r.ident = ident;
             r.intent = intent;
+            r.referrer = referrer;
             r.voiceInteractor = voiceInteractor;
             r.activityInfo = info;
             r.compatInfo = compatInfo;
@@ -637,13 +640,13 @@
         }
 
         public final void scheduleRelaunchActivity(IBinder token,
-                List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
+                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                 int configChanges, boolean notResumed, Configuration config) {
             requestRelaunchActivity(token, pendingResults, pendingNewIntents,
                     configChanges, notResumed, config, true);
         }
 
-        public final void scheduleNewIntent(List<Intent> intents, IBinder token) {
+        public final void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) {
             NewIntentData data = new NewIntentData();
             data.intents = intents;
             data.token = token;
@@ -2234,7 +2237,7 @@
                 activity.attach(appContext, this, getInstrumentation(), r.token,
                         r.ident, app, r.intent, r.activityInfo, title, r.parent,
                         r.embeddedID, r.lastNonConfigurationInstances, config,
-                        r.voiceInteractor);
+                        r.referrer, r.voiceInteractor);
 
                 if (customIntent != null) {
                     activity.mIntent = customIntent;
@@ -2421,8 +2424,7 @@
         }
     }
 
-    private void deliverNewIntents(ActivityClientRecord r,
-            List<Intent> intents) {
+    private void deliverNewIntents(ActivityClientRecord r, List<ReferrerIntent> intents) {
         final int N = intents.size();
         for (int i=0; i<N; i++) {
             Intent intent = intents.get(i);
@@ -2433,8 +2435,7 @@
         }
     }
 
-    public final void performNewIntents(IBinder token,
-            List<Intent> intents) {
+    public final void performNewIntents(IBinder token, List<ReferrerIntent> intents) {
         ActivityClientRecord r = mActivities.get(token);
         if (r != null) {
             final boolean resumed = !r.paused;
@@ -3752,7 +3753,7 @@
     }
 
     public final void requestRelaunchActivity(IBinder token,
-            List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
+            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
             int configChanges, boolean notResumed, Configuration config,
             boolean fromServer) {
         ActivityClientRecord target = null;
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 0123e16..d1b77b9 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -36,6 +36,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -140,19 +141,21 @@
             ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
             Configuration curConfig = Configuration.CREATOR.createFromParcel(data);
             CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
+            String referrer = data.readString();
             IVoiceInteractor voiceInteractor = IVoiceInteractor.Stub.asInterface(
                     data.readStrongBinder());
             int procState = data.readInt();
             Bundle state = data.readBundle();
             PersistableBundle persistentState = data.readPersistableBundle();
             List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
-            List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
+            List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
             boolean notResumed = data.readInt() != 0;
             boolean isForward = data.readInt() != 0;
             ProfilerInfo profilerInfo = data.readInt() != 0
                     ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
-            scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, voiceInteractor,
-                    procState, state, persistentState, ri, pi, notResumed, isForward, profilerInfo);
+            scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, referrer,
+                    voiceInteractor, procState, state, persistentState, ri, pi,
+                    notResumed, isForward, profilerInfo);
             return true;
         }
 
@@ -161,7 +164,7 @@
             data.enforceInterface(IApplicationThread.descriptor);
             IBinder b = data.readStrongBinder();
             List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
-            List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
+            List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
             int configChanges = data.readInt();
             boolean notResumed = data.readInt() != 0;
             Configuration config = null;
@@ -175,7 +178,7 @@
         case SCHEDULE_NEW_INTENT_TRANSACTION:
         {
             data.enforceInterface(IApplicationThread.descriptor);
-            List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
+            List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
             IBinder b = data.readStrongBinder();
             scheduleNewIntent(pi, b);
             return true;
@@ -764,9 +767,9 @@
 
     public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
             ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-            IVoiceInteractor voiceInteractor, int procState, Bundle state,
+            String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
             PersistableBundle persistentState, List<ResultInfo> pendingResults,
-            List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+            List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
             ProfilerInfo profilerInfo) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -776,6 +779,7 @@
         info.writeToParcel(data, 0);
         curConfig.writeToParcel(data, 0);
         compatInfo.writeToParcel(data, 0);
+        data.writeString(referrer);
         data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
         data.writeInt(procState);
         data.writeBundle(state);
@@ -796,7 +800,7 @@
     }
 
     public final void scheduleRelaunchActivity(IBinder token,
-            List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
+            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
             int configChanges, boolean notResumed, Configuration config)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -817,7 +821,7 @@
         data.recycle();
     }
 
-    public void scheduleNewIntent(List<Intent> intents, IBinder token)
+    public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 0092ee7..2784d44 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -38,6 +38,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 final class BackStackState implements Parcelable {
     final int[] mOps;
@@ -1055,7 +1056,7 @@
     }
 
     private static ArrayList<View> captureExitingViews(Transition exitTransition,
-            Fragment outFragment, ArrayMap<String, View> namedViews) {
+            Fragment outFragment, ArrayMap<String, View> namedViews, View nonExistentView) {
         ArrayList<View> viewList = null;
         if (exitTransition != null) {
             viewList = new ArrayList<View>();
@@ -1064,7 +1065,10 @@
             if (namedViews != null) {
                 viewList.removeAll(namedViews.values());
             }
-            addTargets(exitTransition, viewList);
+            if (!viewList.isEmpty()) {
+                viewList.add(nonExistentView);
+                addTargets(exitTransition, viewList);
+            }
         }
         return viewList;
     }
@@ -1132,11 +1136,8 @@
                             namedViews = mapSharedElementsIn(state, isBack, inFragment);
                             removeTargets(sharedElementTransition, sharedElementTargets);
                             sharedElementTargets.clear();
-                            if (namedViews.isEmpty()) {
-                                sharedElementTargets.add(state.nonExistentView);
-                            } else {
-                                sharedElementTargets.addAll(namedViews.values());
-                            }
+                            sharedElementTargets.add(state.nonExistentView);
+                            sharedElementTargets.addAll(namedViews.values());
 
                             addTargets(sharedElementTransition, sharedElementTargets);
 
@@ -1153,6 +1154,9 @@
                                 if (namedViews != null) {
                                     enteringViews.removeAll(namedViews.values());
                                 }
+                                enteringViews.add(state.nonExistentView);
+                                // We added this earlier to prevent any views being targeted.
+                                enterTransition.removeTarget(state.nonExistentView);
                                 addTargets(enterTransition, enteringViews);
                             }
                             setSharedElementEpicenter(enterTransition, state);
@@ -1293,11 +1297,8 @@
             ArrayList<View> sharedElementTargets = new ArrayList<View>();
             if (sharedElementTransition != null) {
                 namedViews = remapSharedElements(state, outFragment, isBack);
-                if (namedViews.isEmpty()) {
-                    sharedElementTargets.add(state.nonExistentView);
-                } else {
-                    sharedElementTargets.addAll(namedViews.values());
-                }
+                sharedElementTargets.add(state.nonExistentView);
+                sharedElementTargets.addAll(namedViews.values());
                 addTargets(sharedElementTransition, sharedElementTargets);
 
                 // Notify the start of the transition.
@@ -1310,7 +1311,7 @@
             }
 
             ArrayList<View> exitingViews = captureExitingViews(exitTransition, outFragment,
-                    namedViews);
+                    namedViews, state.nonExistentView);
             if (exitingViews == null || exitingViews.isEmpty()) {
                 exitTransition = null;
             }
@@ -1388,20 +1389,69 @@
         }
     }
 
-    private static void removeTargets(Transition transition, ArrayList<View> views) {
-        int numViews = views.size();
-        for (int i = 0; i < numViews; i++) {
-            transition.removeTarget(views.get(i));
+    /**
+     * This method removes the views from transitions that target ONLY those views.
+     * The views list should match those added in addTargets and should contain
+     * one view that is not in the view hierarchy (state.nonExistentView).
+     */
+    public static void removeTargets(Transition transition, ArrayList<View> views) {
+        if (transition instanceof TransitionSet) {
+            TransitionSet set = (TransitionSet) transition;
+            int numTransitions = set.getTransitionCount();
+            for (int i = 0; i < numTransitions; i++) {
+                Transition child = set.getTransitionAt(i);
+                removeTargets(child, views);
+            }
+        } else if (!hasSimpleTarget(transition)) {
+            List<View> targets = transition.getTargets();
+            if (targets != null && targets.size() == views.size() &&
+                    targets.containsAll(views)) {
+                // We have an exact match. We must have added these earlier in addTargets
+                for (int i = views.size() - 1; i >= 0; i--) {
+                    transition.removeTarget(views.get(i));
+                }
+            }
         }
     }
 
-    private static void addTargets(Transition transition, ArrayList<View> views) {
-        int numViews = views.size();
-        for (int i = 0; i < numViews; i++) {
-            transition.addTarget(views.get(i));
+    /**
+     * This method adds views as targets to the transition, but only if the transition
+     * doesn't already have a target. It is best for views to contain one View object
+     * that does not exist in the view hierarchy (state.nonExistentView) so that
+     * when they are removed later, a list match will suffice to remove the targets.
+     * Otherwise, if you happened to have targeted the exact views for the transition,
+     * the removeTargets call will remove them unexpectedly.
+     */
+    public static void addTargets(Transition transition, ArrayList<View> views) {
+        if (transition instanceof TransitionSet) {
+            TransitionSet set = (TransitionSet) transition;
+            int numTransitions = set.getTransitionCount();
+            for (int i = 0; i < numTransitions; i++) {
+                Transition child = set.getTransitionAt(i);
+                addTargets(child, views);
+            }
+        } else if (!hasSimpleTarget(transition)) {
+            List<View> targets = transition.getTargets();
+            if (isNullOrEmpty(targets)) {
+                // We can just add the target views
+                int numViews = views.size();
+                for (int i = 0; i < numViews; i++) {
+                    transition.addTarget(views.get(i));
+                }
+            }
         }
     }
 
+    private static boolean hasSimpleTarget(Transition transition) {
+        return !isNullOrEmpty(transition.getTargetIds()) ||
+                !isNullOrEmpty(transition.getTargetNames()) ||
+                !isNullOrEmpty(transition.getTargetTypes());
+    }
+
+    private static boolean isNullOrEmpty(List list) {
+        return list == null || list.isEmpty();
+    }
+
     /**
      * Remaps a name-to-View map, substituting different names for keys.
      *
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index f53075c..42acbc6 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -35,6 +35,7 @@
 import android.os.IInterface;
 import android.service.voice.IVoiceInteractionSession;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
 
 import java.io.FileDescriptor;
 import java.util.List;
@@ -59,14 +60,14 @@
     void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
     void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
             ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-            IVoiceInteractor voiceInteractor, int procState, Bundle state,
+            String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
             PersistableBundle persistentState, List<ResultInfo> pendingResults,
-            List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+            List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
             ProfilerInfo profilerInfo) throws RemoteException;
     void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
-            List<Intent> pendingNewIntents, int configChanges,
+            List<ReferrerIntent> pendingNewIntents, int configChanges,
             boolean notResumed, Configuration config) throws RemoteException;
-    void scheduleNewIntent(List<Intent> intent, IBinder token) throws RemoteException;
+    void scheduleNewIntent(List<ReferrerIntent> intent, IBinder token) throws RemoteException;
     void scheduleDestroyActivity(IBinder token, boolean finished,
             int configChanges) throws RemoteException;
     void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 60a013e..d96153a 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -45,6 +45,7 @@
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 import android.view.Window;
+import com.android.internal.content.ReferrerIntent;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -1042,7 +1043,7 @@
         activity.attach(context, aThread, this, token, 0, application, intent,
                 info, title, parent, id,
                 (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
-                new Configuration(), null);
+                new Configuration(), null, null);
         return activity;
     }
 
@@ -1207,7 +1208,17 @@
      * @param intent The new intent being received.
      */
     public void callActivityOnNewIntent(Activity activity, Intent intent) {
-        activity.onNewIntent(intent);
+        final String oldReferrer = activity.mReferrer;
+        try {
+            try {
+                activity.mReferrer = ((ReferrerIntent)intent).mReferrer;
+            } catch (ClassCastException e) {
+                activity.mReferrer = null;
+            }
+            activity.onNewIntent(intent);
+        } finally {
+            activity.mReferrer = oldReferrer;
+        }
     }
 
     /**
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index b654a6a..873e337 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.util.Log;
 import android.view.Window;
+import com.android.internal.content.ReferrerIntent;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -310,8 +311,8 @@
                 if (aInfo.launchMode != ActivityInfo.LAUNCH_MULTIPLE ||
                         (intent.getFlags()&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0) {
                     // The activity wants onNewIntent() called.
-                    ArrayList<Intent> intents = new ArrayList<Intent>(1);
-                    intents.add(intent);
+                    ArrayList<ReferrerIntent> intents = new ArrayList<>(1);
+                    intents.add(new ReferrerIntent(intent, mParent.getPackageName()));
                     if (localLOGV) Log.v(TAG, r.id + ": new intent");
                     mActivityThread.performNewIntents(r, intents);
                     r.intent = intent;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e06f034..57f6028 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1401,14 +1401,36 @@
             = "android.intent.extra.ORIGINATING_URI";
 
     /**
-     * Used as a URI extra field with {@link #ACTION_INSTALL_PACKAGE} and
-     * {@link #ACTION_VIEW} to indicate the HTTP referrer URI associated with the Intent
-     * data field or {@link #EXTRA_ORIGINATING_URI}.
+     * This extra can be used with any Intent used to launch an activity, supplying information
+     * about who is launching that activity.  This field contains a {@link android.net.Uri}
+     * object, typically an http: or https: URI of the web site that the referral came from;
+     * it can also use the {@link #URI_ANDROID_APP_SCHEME android-app:} scheme to identify
+     * a native application that it came from.
+     *
+     * <p>To retrieve this value in a client, use {@link android.app.Activity#getReferrer}
+     * instead of directly retrieving the extra.  It is also valid for applications to
+     * instead supply {@link #EXTRA_REFERRER_NAME} for cases where they can only create
+     * a string, not a Uri; the field here, if supplied, will always take precedence,
+     * however.</p>
+     *
+     * @see #EXTRA_REFERRER_NAME
      */
     public static final String EXTRA_REFERRER
             = "android.intent.extra.REFERRER";
 
     /**
+     * Alternate version of {@link #EXTRA_REFERRER} that supplies the URI as a String rather
+     * than a {@link android.net.Uri} object.  Only for use in cases where Uri objects can
+     * not be created, in particular when Intent extras are supplied through the
+     * {@link #URI_INTENT_SCHEME intent:} or {@link #URI_ANDROID_APP_SCHEME android-app:}
+     * schemes.
+     *
+     * @see #EXTRA_REFERRER
+     */
+    public static final String EXTRA_REFERRER_NAME
+            = "android.intent.extra.REFERRER_NAME";
+
+    /**
      * Used as an int extra field with {@link #ACTION_INSTALL_PACKAGE} and
      * {@link} #ACTION_VIEW} to indicate the uid of the package that initiated the install
      * @hide
@@ -3919,6 +3941,75 @@
      */
     public static final int URI_INTENT_SCHEME = 1<<0;
 
+    /**
+     * Flag for use with {@link #toUri} and {@link #parseUri}: the URI string
+     * always has the "android-app:" scheme.  This is a variation of
+     * {@link #URI_INTENT_SCHEME} whose format is simpler for the case of an
+     * http/https URI being delivered to a specific package name.  The format
+     * is:
+     *
+     * <pre class="prettyprint">
+     * android-app://{package_id}/{scheme}/{host}/{path}{#Intent;...}</pre>
+     *
+     * <p>In this scheme, only the <code>pacakge_id</code> is required, and all
+     * other components can be included as desired.  Note that this can not be
+     * used with intents that have a {@link #setSelector}, since the base intent
+     * will always have an explicit package name.</p>
+     *
+     * <p>Some examples of how this scheme maps to Intent objects:</p>
+     * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
+     *     <colgroup align="left" />
+     *     <colgroup align="left" />
+     *     <thead>
+     *     <tr><th>URI</th> <th>Intent</th></tr>
+     *     </thead>
+     *
+     *     <tbody>
+     *     <tr><td><code>android-app://com.example.app</code></td>
+     *         <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+     *             <tr><td>Action: </td><td>{@link #ACTION_MAIN}</td></tr>
+     *             <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+     *         </table></td>
+     *     </tr>
+     *     <tr><td><code>android-app://com.example.app/http/example.com</code></td>
+     *         <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+     *             <tr><td>Action: </td><td>{@link #ACTION_VIEW}</td></tr>
+     *             <tr><td>Data: </td><td><code>http://example.com/</code></td></tr>
+     *             <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+     *         </table></td>
+     *     </tr>
+     *     <tr><td><code>android-app://com.example.app/http/example.com/foo?1234</code></td>
+     *         <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+     *             <tr><td>Action: </td><td>{@link #ACTION_VIEW}</td></tr>
+     *             <tr><td>Data: </td><td><code>http://example.com/foo?1234</code></td></tr>
+     *             <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+     *         </table></td>
+     *     </tr>
+     *     <tr><td><code>android-app://com.example.app/<br />#Intent;action=com.example.MY_ACTION;end</code></td>
+     *         <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+     *             <tr><td>Action: </td><td><code>com.example.MY_ACTION</code></td></tr>
+     *             <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+     *         </table></td>
+     *     </tr>
+     *     <tr><td><code>android-app://com.example.app/http/example.com/foo?1234<br />#Intent;action=com.example.MY_ACTION;end</code></td>
+     *         <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+     *             <tr><td>Action: </td><td><code>com.example.MY_ACTION</code></td></tr>
+     *             <tr><td>Data: </td><td><code>http://example.com/foo?1234</code></td></tr>
+     *             <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+     *         </table></td>
+     *     </tr>
+     *     <tr><td><code>android-app://com.example.app/<br />#Intent;action=com.example.MY_ACTION;<br />i.some_int=100;S.some_str=hello;end</code></td>
+     *         <td><table border="" style="margin:0" >
+     *             <tr><td>Action: </td><td><code>com.example.MY_ACTION</code></td></tr>
+     *             <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+     *             <tr><td>Extras: </td><td><code>some_int=(int)100<br />some_str=(String)hello</code></td></tr>
+     *         </table></td>
+     *     </tr>
+     *     </tbody>
+     * </table>
+     */
+    public static final int URI_ANDROID_APP_SCHEME = 1<<1;
+
     // ---------------------------------------------------------------------
 
     private String mAction;
@@ -4179,8 +4270,8 @@
      * the scheme and full path.
      *
      * @param uri The URI to turn into an Intent.
-     * @param flags Additional processing flags.  Either 0 or
-     * {@link #URI_INTENT_SCHEME}.
+     * @param flags Additional processing flags.  Either 0,
+     * {@link #URI_INTENT_SCHEME}, or {@link #URI_ANDROID_APP_SCHEME}.
      *
      * @return Intent The newly created Intent object.
      *
@@ -4193,9 +4284,11 @@
     public static Intent parseUri(String uri, int flags) throws URISyntaxException {
         int i = 0;
         try {
-            // Validate intent scheme for if requested.
-            if ((flags&URI_INTENT_SCHEME) != 0) {
-                if (!uri.startsWith("intent:")) {
+            final boolean androidApp = uri.startsWith("android-app:");
+
+            // Validate intent scheme if requested.
+            if ((flags&(URI_INTENT_SCHEME|URI_ANDROID_APP_SCHEME)) != 0) {
+                if (!uri.startsWith("intent:") && !androidApp) {
                     Intent intent = new Intent(ACTION_VIEW);
                     try {
                         intent.setData(Uri.parse(uri));
@@ -4206,24 +4299,40 @@
                 }
             }
 
-            // simple case
             i = uri.lastIndexOf("#");
-            if (i == -1) return new Intent(ACTION_VIEW, Uri.parse(uri));
+            // simple case
+            if (i == -1) {
+                if (!androidApp) {
+                    return new Intent(ACTION_VIEW, Uri.parse(uri));
+                }
 
             // old format Intent URI
-            if (!uri.startsWith("#Intent;", i)) return getIntentOld(uri);
+            } else if (!uri.startsWith("#Intent;", i)) {
+                if (!androidApp) {
+                    return getIntentOld(uri);
+                } else {
+                    i = -1;
+                }
+            }
 
             // new format
             Intent intent = new Intent(ACTION_VIEW);
             Intent baseIntent = intent;
+            boolean explicitAction = false;
+            boolean inSelector = false;
 
             // fetch data part, if present
-            String data = i >= 0 ? uri.substring(0, i) : null;
             String scheme = null;
-            i += "#Intent;".length();
+            String data;
+            if (i >= 0) {
+                data = uri.substring(0, i);
+                i += 8; // length of "#Intent;"
+            } else {
+                data = uri;
+            }
 
             // loop over contents of Intent, all name=value;
-            while (!uri.startsWith("end", i)) {
+            while (i >= 0 && !uri.startsWith("end", i)) {
                 int eq = uri.indexOf('=', i);
                 if (eq < 0) eq = i-1;
                 int semi = uri.indexOf(';', i);
@@ -4232,6 +4341,9 @@
                 // action
                 if (uri.startsWith("action=", i)) {
                     intent.setAction(value);
+                    if (!inSelector) {
+                        explicitAction = true;
+                    }
                 }
 
                 // categories
@@ -4261,7 +4373,11 @@
 
                 // scheme
                 else if (uri.startsWith("scheme=", i)) {
-                    scheme = value;
+                    if (inSelector) {
+                        intent.mData = Uri.parse(value);
+                    } else {
+                        scheme = value;
+                    }
                 }
 
                 // source bounds
@@ -4272,6 +4388,7 @@
                 // selector
                 else if (semi == (i+3) && uri.startsWith("SEL", i)) {
                     intent = new Intent();
+                    inSelector = true;
                 }
 
                 // extra
@@ -4297,9 +4414,11 @@
                 i = semi + 1;
             }
 
-            if (intent != baseIntent) {
+            if (inSelector) {
                 // The Intent had a selector; fix it up.
-                baseIntent.setSelector(intent);
+                if (baseIntent.mPackage == null) {
+                    baseIntent.setSelector(intent);
+                }
                 intent = baseIntent;
             }
 
@@ -4309,6 +4428,47 @@
                     if (scheme != null) {
                         data = scheme + ':' + data;
                     }
+                } else if (data.startsWith("android-app:")) {
+                    if (data.charAt(12) == '/' && data.charAt(13) == '/') {
+                        // Correctly formed android-app, first part is package name.
+                        int end = data.indexOf('/', 14);
+                        if (end < 0) {
+                            // All we have is a package name.
+                            intent.mPackage = data.substring(14);
+                            if (!explicitAction) {
+                                intent.setAction(ACTION_MAIN);
+                            }
+                            data = "";
+                        } else {
+                            // Target the Intent at the given package name always.
+                            String authority = null;
+                            intent.mPackage = data.substring(14, end);
+                            int newEnd;
+                            if (end < data.length() && (newEnd=data.indexOf('/', end+1)) >= 0) {
+                                // Found a scheme, remember it.
+                                scheme = data.substring(end+1, newEnd);
+                                end = newEnd;
+                                if (end < data.length() && (newEnd=data.indexOf('/', end+1)) >= 0) {
+                                    // Found a authority, remember it.
+                                    authority = data.substring(end+1, newEnd);
+                                    end = newEnd;
+                                }
+                            }
+                            if (scheme == null) {
+                                // If there was no scheme, then this just targets the package.
+                                if (!explicitAction) {
+                                    intent.setAction(ACTION_MAIN);
+                                }
+                                data = "";
+                            } else if (authority == null) {
+                                data = scheme + ":";
+                            } else {
+                                data = scheme + "://" + authority + data.substring(end);
+                            }
+                        }
+                    } else {
+                        data = "";
+                    }
                 }
 
                 if (data.length() > 0) {
@@ -7084,14 +7244,53 @@
      * <p>You can convert the returned string back to an Intent with
      * {@link #getIntent}.
      *
-     * @param flags Additional operating flags.  Either 0 or
-     * {@link #URI_INTENT_SCHEME}.
+     * @param flags Additional operating flags.  Either 0,
+     * {@link #URI_INTENT_SCHEME}, or {@link #URI_ANDROID_APP_SCHEME}.
      *
      * @return Returns a URI encoding URI string describing the entire contents
      * of the Intent.
      */
     public String toUri(int flags) {
         StringBuilder uri = new StringBuilder(128);
+        if ((flags&URI_ANDROID_APP_SCHEME) != 0) {
+            if (mPackage == null) {
+                throw new IllegalArgumentException(
+                        "Intent must include an explicit package name to build an android-app: "
+                        + this);
+            }
+            uri.append("android-app://");
+            uri.append(mPackage);
+            String scheme = null;
+            if (mData != null) {
+                scheme = mData.getScheme();
+                if (scheme != null) {
+                    uri.append('/');
+                    uri.append(scheme);
+                    String authority = mData.getEncodedAuthority();
+                    if (authority != null) {
+                        uri.append('/');
+                        uri.append(authority);
+                        String path = mData.getEncodedPath();
+                        if (path != null) {
+                            uri.append(path);
+                        }
+                        String queryParams = mData.getEncodedQuery();
+                        if (queryParams != null) {
+                            uri.append('?');
+                            uri.append(queryParams);
+                        }
+                        String fragment = mData.getEncodedFragment();
+                        if (fragment != null) {
+                            uri.append('#');
+                            uri.append(fragment);
+                        }
+                    }
+                }
+            }
+            toUriFragment(uri, null, scheme == null ? Intent.ACTION_MAIN : Intent.ACTION_VIEW,
+                    mPackage, flags);
+            return uri.toString();
+        }
         String scheme = null;
         if (mData != null) {
             String data = mData.toString();
@@ -7121,27 +7320,38 @@
             uri.append("intent:");
         }
 
-        uri.append("#Intent;");
+        toUriFragment(uri, scheme, Intent.ACTION_VIEW, null, flags);
 
-        toUriInner(uri, scheme, flags);
+        return uri.toString();
+    }
+
+    private void toUriFragment(StringBuilder uri, String scheme, String defAction,
+            String defPackage, int flags) {
+        StringBuilder frag = new StringBuilder(128);
+
+        toUriInner(frag, scheme, defAction, defPackage, flags);
         if (mSelector != null) {
             uri.append("SEL;");
             // Note that for now we are not going to try to handle the
             // data part; not clear how to represent this as a URI, and
             // not much utility in it.
-            mSelector.toUriInner(uri, null, flags);
+            mSelector.toUriInner(frag, mSelector.mData != null ? mSelector.mData.getScheme() : null,
+                    null, null, flags);
         }
 
-        uri.append("end");
-
-        return uri.toString();
+        if (frag.length() > 0) {
+            uri.append("#Intent;");
+            uri.append(frag);
+            uri.append("end");
+        }
     }
 
-    private void toUriInner(StringBuilder uri, String scheme, int flags) {
+    private void toUriInner(StringBuilder uri, String scheme, String defAction,
+            String defPackage, int flags) {
         if (scheme != null) {
             uri.append("scheme=").append(scheme).append(';');
         }
-        if (mAction != null) {
+        if (mAction != null && !mAction.equals(defAction)) {
             uri.append("action=").append(Uri.encode(mAction)).append(';');
         }
         if (mCategories != null) {
@@ -7155,7 +7365,7 @@
         if (mFlags != 0) {
             uri.append("launchFlags=0x").append(Integer.toHexString(mFlags)).append(';');
         }
-        if (mPackage != null) {
+        if (mPackage != null && !mPackage.equals(defPackage)) {
             uri.append("package=").append(Uri.encode(mPackage)).append(';');
         }
         if (mComponent != null) {
diff --git a/core/java/android/content/pm/LabeledIntent.aidl b/core/java/android/content/pm/LabeledIntent.aidl
new file mode 100644
index 0000000..ad96759
--- /dev/null
+++ b/core/java/android/content/pm/LabeledIntent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+parcelable LabeledIntent;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 654a8ed..5c433c1 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2582,15 +2582,21 @@
      * Returns true if this ViewGroup should be considered as a single entity for removal
      * when executing an Activity transition. If this is false, child elements will move
      * individually during the transition.
+     *
      * @return True if the ViewGroup should be acted on together during an Activity transition.
-     * The default value is false when the background is null and true when the background
-     * is not null or if {@link #getTransitionName()} is not null.
+     * The default value is true when there is a non-null background or if
+     * {@link #getTransitionName()} is not null or if a
+     * non-null {@link android.view.ViewOutlineProvider} other than
+     * {@link android.view.ViewOutlineProvider#BACKGROUND} was given to
+     * {@link #setOutlineProvider(ViewOutlineProvider)} and false otherwise.
      */
     public boolean isTransitionGroup() {
         if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
             return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
         } else {
-            return getBackground() != null || getTransitionName() != null;
+            final ViewOutlineProvider outlineProvider = getOutlineProvider();
+            return getBackground() != null || getTransitionName() != null ||
+                    (outlineProvider != null && outlineProvider != ViewOutlineProvider.BACKGROUND);
         }
     }
 
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 78ee247..7d01321 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -607,23 +607,32 @@
      */
     @Override
     public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
-        if (pickerIndex == HOUR_INDEX) {
-            if (mAllowAutoAdvance && autoAdvance) {
-                updateHeaderHour(newValue, false);
-                setCurrentItemShowing(MINUTE_INDEX, true, false);
-                mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes);
-            } else {
-                updateHeaderHour(newValue, true);
-            }
-        } else if (pickerIndex == MINUTE_INDEX){
-            updateHeaderMinute(newValue, true);
-        } else if (pickerIndex == AMPM_INDEX) {
-            updateAmPmLabelStates(newValue);
-        } else if (pickerIndex == ENABLE_PICKER_INDEX) {
-            if (!isTypedTimeFullyLegal()) {
-                mTypedTimes.clear();
-            }
-            finishKbMode();
+        switch (pickerIndex) {
+            case HOUR_INDEX:
+                if (mAllowAutoAdvance && autoAdvance) {
+                    updateHeaderHour(newValue, false);
+                    setCurrentItemShowing(MINUTE_INDEX, true, false);
+                    mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes);
+                } else {
+                    updateHeaderHour(newValue, true);
+                }
+                break;
+            case MINUTE_INDEX:
+                updateHeaderMinute(newValue, true);
+                break;
+            case AMPM_INDEX:
+                updateAmPmLabelStates(newValue);
+                break;
+            case ENABLE_PICKER_INDEX:
+                if (!isTypedTimeFullyLegal()) {
+                    mTypedTimes.clear();
+                }
+                finishKbMode();
+                break;
+        }
+
+        if (mOnTimeChangedListener != null) {
+            mOnTimeChangedListener.onTimeChanged(mDelegator, getCurrentHour(), getCurrentMinute());
         }
     }
 
diff --git a/core/java/com/android/internal/content/ReferrerIntent.aidl b/core/java/com/android/internal/content/ReferrerIntent.aidl
new file mode 100644
index 0000000..7cf6774
--- /dev/null
+++ b/core/java/com/android/internal/content/ReferrerIntent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.content;
+
+parcelable ReferrerIntent;
diff --git a/core/java/com/android/internal/content/ReferrerIntent.java b/core/java/com/android/internal/content/ReferrerIntent.java
new file mode 100644
index 0000000..8d9a1cf
--- /dev/null
+++ b/core/java/com/android/internal/content/ReferrerIntent.java
@@ -0,0 +1,51 @@
+/*
+ * 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.internal.content;
+
+import android.content.Intent;
+import android.os.Parcel;
+
+/**
+ * Subclass of Intent that also contains referrer (as a package name) information.
+ */
+public class ReferrerIntent extends Intent {
+    public final String mReferrer;
+
+    public ReferrerIntent(Intent baseIntent, String referrer) {
+        super(baseIntent);
+        mReferrer = referrer;
+    }
+
+    public void writeToParcel(Parcel dest, int parcelableFlags) {
+        super.writeToParcel(dest, parcelableFlags);
+        dest.writeString(mReferrer);
+    }
+
+    ReferrerIntent(Parcel in) {
+        readFromParcel(in);
+        mReferrer = in.readString();
+    }
+
+    public static final Creator<ReferrerIntent> CREATOR = new Creator<ReferrerIntent>() {
+        public ReferrerIntent createFromParcel(Parcel source) {
+            return new ReferrerIntent(source);
+        }
+        public ReferrerIntent[] newArray(int size) {
+            return new ReferrerIntent[size];
+        }
+    };
+}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fe87919..d6bc38f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -326,6 +326,8 @@
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
     <string name="low_memory" product="watch">Watch storage is full. Delete some files to free space.</string>
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
+    <string name="low_memory" product="tv">TV storage is full. Delete some files to free space.</string>
+    <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
     <string name="low_memory" product="default">Phone storage is full. Delete some files to free space.</string>
 
     <!-- SSL CA cert notification --> <skip />
@@ -348,6 +350,8 @@
     <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
     <string name="power_dialog" product="tablet">Tablet options</string>
     <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
+    <string name="power_dialog" product="tv">TV options</string>
+    <!-- Title for the Phone Options dialog to lock the screen, turn off the phone etc. -->
     <string name="power_dialog" product="default">Phone options</string>
     <!-- Button to turn on silent mode, within the Phone Options dialog -->
     <string name="silent_mode">Silent mode</string>
@@ -372,6 +376,9 @@
     <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the phone, there will
          be a confirmation dialog.  This is the message. -->
     <string name="shutdown_confirm" product="tablet">Your tablet will shut down.</string>
+    <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the TV, there will
+         be a confirmation dialog.  This is the message. -->
+    <string name="shutdown_confirm" product="tv">Your TV will shut down.</string>
     <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the watch, there will
          be a confirmation dialog.  This is the message. -->
     <string name="shutdown_confirm" product="watch">Your watch will shut down.</string>
@@ -408,6 +415,8 @@
     <!-- Title of the Global Actions Dialog -->
     <string name="global_actions" product="tablet">Tablet options</string>
     <!-- Title of the Global Actions Dialog -->
+    <string name="global_actions" product="tv">TV options</string>
+    <!-- Title of the Global Actions Dialog -->
     <string name="global_actions" product="default">Phone options</string>
 
     <!-- label for item that locks the phone in the phone options dialog -->
@@ -745,6 +754,10 @@
       messages stored on your tablet or SIM card. This allows the app to read all
       SMS messages, regardless of content or confidentiality.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_readSms" product="tv">Allows the app to read SMS
+      messages stored on your TV or SIM card. This allows the app to read all
+      SMS messages, regardless of content or confidentiality.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readSms" product="default">Allows the app to read SMS
       messages stored on your phone or SIM card. This allows the app to read all
       SMS messages, regardless of content or confidentiality.</string>
@@ -756,6 +769,10 @@
       to SMS messages stored on your tablet or SIM card. Malicious apps
       may delete your messages.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_writeSms" product="tv">Allows the app to write
+      to SMS messages stored on your TV or SIM card. Malicious apps
+      may delete your messages.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeSms" product="default">Allows the app to write
       to SMS messages stored on your phone or SIM card. Malicious apps
       may delete your messages.</string>
@@ -1077,6 +1094,10 @@
         its own input events (key presses, etc.) to other apps. Malicious
         apps may use this to take over the tablet.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_injectEvents" product="tv">Allows the app to deliver
+        its own input events (key presses, etc.) to other apps. Malicious
+        apps may use this to take over the TV.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_injectEvents" product="default">Allows the app to deliver
         its own input events (key presses, etc.) to other apps. Malicious
         apps may use this to take over the phone.</string>
@@ -1216,6 +1237,8 @@
     <string name="permlab_persistentActivity">make app always run</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_persistentActivity" product="tablet">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the tablet.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_persistentActivity" product="tv">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the TV.</string>
     <string name="permdesc_persistentActivity" product="default">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the phone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1253,6 +1276,10 @@
         by deleting files in the cache directories of other applications.  This may cause other
         applications to start up more slowly as they need to re-retrieve their data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_clearAppCache" product="tv">Allows the app to free TV storage
+        by deleting files in the cache directories of other applications.  This may cause other
+        applications to start up more slowly as they need to re-retrieve their data.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_clearAppCache" product="default">Allows the app to free phone storage
         by deleting files in the cache directories of other applications.  This may cause other
         applications to start up more slowly as they need to re-retrieve their data.</string>
@@ -1270,6 +1297,11 @@
         information about what you are doing with the tablet, potentially
         including personal or private information.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_readLogs" product="tv">Allows the app to read from the
+        system\'s various log files.  This allows it to discover general
+        information about what you are doing with the TV, potentially
+        including personal or private information.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readLogs" product="default">Allows the app to read from the
         system\'s various log files.  This allows it to discover general
         information about what you are doing with the phone, potentially
@@ -1312,6 +1344,12 @@
         possible to get app components into an unusable, inconsistent, or unstable state.
     </string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_changeComponentState" product="tv">Allows the app to change whether a
+        component of another app is enabled or not. Malicious apps may use this
+        to disable important TV capabilities. Care must be used with this permission, as it is
+        possible to get app components into an unusable, inconsistent, or unstable state.
+    </string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_changeComponentState" product="default">Allows the app to change whether a
         component of another app is enabled or not. Malicious apps may use this
         to disable important phone capabilities. Care must be used with this permission, as it is
@@ -1359,6 +1397,11 @@
         This can make it take longer to start the tablet and allow the
         app to slow down the overall tablet by always running.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_receiveBootCompleted" product="tv">Allows the app to
+        have itself started as soon as the system has finished booting.
+        This can make it take longer to start the TV and allow the
+        app to slow down the overall tablet by always running.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_receiveBootCompleted" product="default">Allows the app to
         have itself started as soon as the system has finished booting.
         This can make it take longer to start the phone and allow the
@@ -1372,6 +1415,11 @@
     may make the tablet slow or unstable by causing it to use too much memory.
     </string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_broadcastSticky" product="tv">Allows the app to
+    send sticky broadcasts, which remain after the broadcast ends. Excessive use
+    may make the TV slow or unstable by causing it to use too much memory.
+    </string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_broadcastSticky" product="default">Allows the app to
     send sticky broadcasts, which remain after the broadcast ends. Excessive
     use may make the phone slow or unstable by causing it to use too
@@ -1387,6 +1435,13 @@
       data, and malicious apps may share contact data without your
       knowledge.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_readContacts" product="tv">Allows the app to read
+      data about your contacts stored on your TV, including the frequency
+      with which you\'ve called, emailed, or communicated in other ways with
+      specific individuals. This permission allows apps to save your contact
+      data, and malicious apps may share contact data without your
+      knowledge.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readContacts" product="default">Allows the app to
       read data about your contacts stored on your phone, including the
       frequency with which you\'ve called, emailed, or communicated in other ways
@@ -1403,6 +1458,12 @@
       with specific contacts. This permission allows apps to delete contact
       data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_writeContacts" product="tv">Allows the app to
+      modify the data about your contacts stored on your TV, including the
+      frequency with which you\'ve called, emailed, or communicated in other ways
+      with specific contacts. This permission allows apps to delete contact
+      data.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeContacts" product="default">Allows the app to
     modify the data about your contacts stored on your phone, including the
     frequency with which you\'ve called, emailed, or communicated in other ways
@@ -1417,6 +1478,11 @@
      This permission allows apps to save your call log data, and malicious apps
      may share call log data without your knowledge.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_readCallLog" product="tv">Allows the app to read
+     your TV\'s call log, including data about incoming and outgoing calls.
+     This permission allows apps to save your call log data, and malicious apps
+     may share call log data without your knowledge.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readCallLog" product="default">Allows the app to read
       your phone\'s call log, including data about incoming and outgoing calls.
       This permission allows apps to save your call log data, and malicious apps
@@ -1428,6 +1494,9 @@
     <string name="permdesc_writeCallLog" product="tablet">Allows the app to modify your tablet\'s call log, including data about incoming and outgoing calls.
         Malicious apps may use this to erase or modify your call log.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_writeCallLog" product="tv">Allows the app to modify your TV\'s call log, including data about incoming and outgoing calls.
+        Malicious apps may use this to erase or modify your call log.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeCallLog" product="default">Allows the app to modify your phone\'s call log, including data about incoming and outgoing calls.
         Malicious apps may use this to erase or modify your call log.</string>
 
@@ -1475,12 +1544,16 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readCalendar">read calendar events plus confidential information</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-
     <string name="permdesc_readCalendar" product="tablet">Allows the app to read
        all calendar events stored on your tablet, including those of friends or
        co-workers. This may allow the app to share or save your calendar data,
        regardless of confidentiality or sensitivity.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_readCalendar" product="tv">Allows the app to read
+       all calendar events stored on your TV, including those of friends or
+       co-workers. This may allow the app to share or save your calendar data,
+       regardless of confidentiality or sensitivity.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readCalendar" product="default">Allows the app to
        read all calendar events stored on your phone, including those of friends
        or co-workers. This may allow the app to share or save your calendar data,
@@ -1489,17 +1562,23 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeCalendar">add or modify calendar events and send email to guests without owners\' knowledge</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-
-<string name="permdesc_writeCalendar" product="tablet">Allows the app to
-     add, remove, change events that you can modify on your tablet, including
-     those of friends or co-workers. This may allow the app to send messages
-     that appear to come from calendar owners, or modify events without the
-     owners\' knowledge.</string>
-<string name="permdesc_writeCalendar" product="default">Allows the app to
-     add, remove, change events that you can modify on your phone, including
-     those of friends or co-workers. This may allow the app to send messages
-     that appear to come from calendar owners, or modify events without the
-     owners\' knowledge.</string>
+    <string name="permdesc_writeCalendar" product="tablet">Allows the app to
+        add, remove, change events that you can modify on your tablet, including
+        those of friends or co-workers. This may allow the app to send messages
+        that appear to come from calendar owners, or modify events without the
+        owners\' knowledge.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_writeCalendar" product="tv">Allows the app to
+        add, remove, change events that you can modify on your TV, including
+        those of friends or co-workers. This may allow the app to send messages
+        that appear to come from calendar owners, or modify events without the
+        owners\' knowledge.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_writeCalendar" product="default">Allows the app to
+        add, remove, change events that you can modify on your phone, including
+        those of friends or co-workers. This may allow the app to send messages
+        that appear to come from calendar owners, or modify events without the
+        owners\' knowledge.</string>
 
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1635,21 +1714,30 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_brick" product="tablet">permanently disable tablet</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_brick" product="tv">permanently disable TV</string>
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_brick" product="default">permanently disable phone</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_brick" product="tablet">Allows the app to
         disable the entire tablet permanently. This is very dangerous.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_brick" product="tv">Allows the app to
+        disable the entire TV permanently. This is very dangerous.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_brick" product="default">Allows the app to
         disable the entire phone permanently. This is very dangerous.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_reboot" product="tablet">force tablet reboot</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_reboot" product="tv">force TV reboot</string>
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_reboot" product="default">force phone reboot</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_reboot" product="tablet">Allows the app to force the tablet to reboot.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_reboot" product="tv">Allows the app to force the TV to reboot.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_reboot" product="default">Allows the app to force the phone to reboot.</string>
 
 
@@ -1744,6 +1832,8 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_performCdmaProvisioning" product="tablet">directly start CDMA tablet setup</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_performCdmaProvisioning" product="tv">directly start CDMA TV setup</string>
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_performCdmaProvisioning" product="default">directly start CDMA phone setup</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_performCdmaProvisioning">Allows the app to start CDMA provisioning.
@@ -1797,10 +1887,14 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_wakeLock" product="tv">prevent TV from sleeping</string>
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="default">prevent phone from sleeping</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_wakeLock" product="tablet">Allows the app to prevent the tablet from going to sleep.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_wakeLock" product="tv">Allows the app to prevent the TV from going to sleep.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_wakeLock" product="default">Allows the app to prevent the phone from going to sleep.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1808,17 +1902,24 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_transmitIr" product="tablet">Allows the app to use the tablet\'s infrared transmitter.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_transmitIr" product="tv">Allows the app to use the TV\'s infrared transmitter.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_transmitIr" product="default">Allows the app to use the phone\'s infrared transmitter.</string>
 
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_devicePower" product="tablet">power tablet on or off</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_devicePower" product="tv">power TV on or off</string>
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_devicePower" product="default">power phone on or off</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_devicePower" product="tablet">Allows the app to turn the
         tablet on or off.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_devicePower" product="tv">Allows the app to turn the
+        TV on or off.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_devicePower" product="default">Allows the app to turn the phone on or off.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1833,6 +1934,10 @@
         allowing complete access to the tablet hardware. Only available
         when a tablet is running in manufacturer test mode.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_factoryTest" product="tv">Run as a low-level manufacturer test,
+        allowing complete access to the TV hardware. Only available
+        when a TV is running in manufacturer test mode.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_factoryTest" product="default">Run as a low-level manufacturer test,
         allowing complete access to the phone hardware. Only available
         when a phone is running in manufacturer test mode.</string>
@@ -1859,6 +1964,8 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setTime" product="tablet">Allows the app to change the tablet\'s clock time.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_setTime" product="tv">Allows the app to change the TV\'s clock time.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setTime" product="default">Allows the app to change the phone\'s clock time.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1866,6 +1973,8 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setTimeZone" product="tablet">Allows the app to change the tablet\'s time zone.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_setTimeZone" product="tv">Allows the app to change the TV\'s time zone.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setTimeZone" product="default">Allows the app to change the phone\'s time zone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1880,6 +1989,10 @@
       the list of accounts known by the tablet.  This may include any accounts
       created by applications you have installed.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_getAccounts" product="tv">Allows the app to get
+      the list of accounts known by the TV.  This may include any accounts
+      created by applications you have installed.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getAccounts" product="default">Allows the app to get
       the list of accounts known by the phone.  This may include any accounts
       created by applications you have installed.</string>
@@ -1961,6 +2074,10 @@
     <string name="permdesc_changeWifiMulticastState" product="tablet">Allows the app to receive
       packets sent to all devices on a Wi-Fi network using multicast addresses,
       not just your tablet.  It uses more power than the non-multicast mode.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_changeWifiMulticastState" product="tv">Allows the app to receive
+      packets sent to all devices on a Wi-Fi network using multicast addresses,
+      not just your TV.  It uses more power than the non-multicast mode.</string>
     <string name="permdesc_changeWifiMulticastState" product="default">Allows the app to receive
       packets sent to all devices on a Wi-Fi network using multicast addresses,
       not just your phone.  It uses more power than the non-multicast mode.</string>
@@ -1972,6 +2089,10 @@
       configure the local Bluetooth tablet, and to discover and pair with remote
       devices.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bluetoothAdmin" product="tv">Allows the app to
+      configure the local Bluetooth TV, and to discover and pair with remote
+      devices.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothAdmin" product="default">Allows the app to configure
       the local Bluetooth phone, and to discover and pair with remote devices.</string>
 
@@ -1981,6 +2102,9 @@
     <string name="permdesc_bluetoothPriv" product="tablet">Allows the app to
       pair with remote devices without user interaction.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bluetoothPriv" product="tv">Allows the app to
+      pair with remote devices without user interaction.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothPriv" product="default">Allows the app to
       pair with remote devices without user interaction.</string>
 
@@ -1989,6 +2113,8 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothMap" product="tablet">Allows the app to access Bluetooth MAP data.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bluetoothMap" product="tv">Allows the app to access Bluetooth MAP data.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothMap" product="default">Allows the app to access Bluetooth MAP data.</string>
 
     <string name="permlab_accessWimaxState">connect and disconnect from WiMAX</string>
@@ -1999,6 +2125,8 @@
     <string name="permlab_changeWimaxState">Change WiMAX state</string>
     <string name="permdesc_changeWimaxState" product="tablet">Allows the app to
       connect the tablet to and disconnect the tablet from WiMAX networks.</string>
+    <string name="permdesc_changeWimaxState" product="tv">Allows the app to
+      connect the TV to and disconnect the TV from WiMAX networks.</string>
     <string name="permdesc_changeWimaxState" product="default">Allows the app to
       connect the phone to and disconnect the phone from WiMAX networks.</string>
 
@@ -2008,6 +2136,9 @@
     <string name="permdesc_scoreNetworks" product="tablet">Allows the app to
       rank networks and influence which networks the tablet should prefer.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_scoreNetworks" product="tv">Allows the app to
+      rank networks and influence which networks the TV should prefer.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_scoreNetworks" product="default">Allows the app to
         rank networks and influence which networks the phone should prefer.</string>
 
@@ -2018,6 +2149,10 @@
       configuration of Bluetooth on the tablet, and to make and accept
       connections with paired devices.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bluetooth" product="tv">Allows the app to view the
+      configuration of Bluetooth on the TV, and to make and accept
+      connections with paired devices.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetooth" product="default">Allows the app to view the
       configuration of the Bluetooth on the phone, and to make and accept
       connections with paired devices.</string>
@@ -2222,6 +2357,10 @@
     typed when unlocking the screen, and lock the tablet or erase all the tablet\'s
     data if too many incorrect passwords are typed.</string>
     <!-- Description of policy access to watch user login attempts -->
+    <string name="policydesc_watchLogin" product="TV">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the TV or erase all the TV\'s
+    data if too many incorrect passwords are typed.</string>
+    <!-- Description of policy access to watch user login attempts -->
     <string name="policydesc_watchLogin" product="default">Monitor the number of incorrect passwords
     typed. when unlocking the screen, and lock the phone or erase all the phone\'s
     data if too many incorrect passwords are typed.</string>
@@ -2238,6 +2377,8 @@
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData" product="tv">Erase the TV\'s data without warning by performing a factory data reset.</string>
+    <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
     <string name="policylab_setGlobalProxy">Set the device global proxy</string>
     <!-- Description of policy access to wipe the user's data -->
@@ -2545,6 +2686,8 @@
     <!-- Shown in the lock screen when there is no SIM card. -->
     <string name="lockscreen_missing_sim_message" product="tablet">No SIM card in tablet.</string>
     <!-- Shown in the lock screen when there is no SIM card. -->
+    <string name="lockscreen_missing_sim_message" product="tv">No SIM card in TV.</string>
+    <!-- Shown in the lock screen when there is no SIM card. -->
     <string name="lockscreen_missing_sim_message" product="default">No SIM card in phone.</string>
     <!-- Shown in the lock screen to ask the user to insert a SIM card. -->
     <string name="lockscreen_missing_sim_instructions">Insert a SIM card.</string>
@@ -2625,6 +2768,15 @@
 
     <!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
          where they will be locked out and may have to enter an alternate username/password to unlock the phone -->
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tv">
+        You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
+       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       you will be asked to unlock your TV using your Google signin.\n\n
+       Try again in <xliff:g id="number">%d</xliff:g> seconds.
+    </string>
+
+    <!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
+         where they will be locked out and may have to enter an alternate username/password to unlock the phone -->
     <string name="lockscreen_failed_attempts_almost_glogin" product="default">
         You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
        After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
@@ -2642,6 +2794,14 @@
 
     <!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
          where the device will be wiped. -->
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv">
+       You have incorrectly attempted to unlock the TV <xliff:g id="number">%d</xliff:g> times.
+       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       the TV will be reset to factory default and all user data will be lost.
+    </string>
+
+    <!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
+         where the device will be wiped. -->
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default">
        You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
        After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
@@ -2657,6 +2817,13 @@
 
     <!-- For the unlock screen, informational message shown in dialog when user has exceeded the
         maximum attempts and the device will now be wiped -->
+    <string name="lockscreen_failed_attempts_now_wiping" product="tv">
+       You have incorrectly attempted to unlock the TV <xliff:g id="number">%d</xliff:g> times.
+       The TV will now be reset to factory default.
+    </string>
+
+    <!-- For the unlock screen, informational message shown in dialog when user has exceeded the
+        maximum attempts and the device will now be wiped -->
     <string name="lockscreen_failed_attempts_now_wiping" product="default">
        You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
        The phone will now be reset to factory default.
@@ -3010,6 +3177,13 @@
         applications with web browsing capabilities.</string>
     <!-- Description of an application permission, listed so the user can choose whether
         they want to allow the application to do this. -->
+    <string name="permdesc_writeHistoryBookmarks" product="tv">Allows the
+        app to modify the Browser\'s history or bookmarks stored on your TV.
+        This may allow the app to erase or modify Browser data.  Note: this
+        permission may note be enforced by third-party browsers or other
+        applications with web browsing capabilities.</string>
+    <!-- Description of an application permission, listed so the user can choose whether
+        they want to allow the application to do this. -->
     <string name="permdesc_writeHistoryBookmarks" product="default">Allows the
         app to modify the Browser\'s history or bookmarks stored on your phone.
         This may allow the app to erase or modify Browser data.  Note:
@@ -3643,6 +3817,7 @@
     <string name="wifi_p2p_show_pin_message">PIN: </string>
 
     <string name="wifi_p2p_frequency_conflict_message" product="tablet">The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tv">The TV will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
     <string name="wifi_p2p_frequency_conflict_message" product="default">The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
 
     <!-- Name of the dialog that lets the user choose an accented character to insert -->
@@ -4352,6 +4527,10 @@
          is connected to a headphone or other wired audio output jack. [CHAR LIMIT=50] -->
     <string name="default_audio_route_name" product="tablet">Tablet</string>
 
+    <!-- Name of the default audio route for tablets when nothing
+         is connected to a headphone or other wired audio output jack. [CHAR LIMIT=50] -->
+    <string name="default_audio_route_name" product="tv">TV</string>
+
     <!-- Name of the default audio route when nothing is connected to
          a headphone or other wired audio output jack. [CHAR LIMIT=50] -->
     <string name="default_audio_route_name" product="default">Phone</string>
@@ -4502,6 +4681,12 @@
        the tablet will be reset to factory default and all user data will be lost.
     </string>
     <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
+    <string name="kg_failed_attempts_almost_at_wipe" product="tv">
+       You have incorrectly attempted to unlock the TV <xliff:g id="number">%d</xliff:g> times.
+       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       the TV will be reset to factory default and all user data will be lost.
+    </string>
+    <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
     <string name="kg_failed_attempts_almost_at_wipe" product="default">
        You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
        After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
@@ -4513,6 +4698,11 @@
        The tablet will now be reset to factory default.
     </string>
     <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
+    <string name="kg_failed_attempts_now_wiping" product="tv">
+       You have incorrectly attempted to unlock the TV <xliff:g id="number">%d</xliff:g> times.
+       The TV will now be reset to factory default.
+    </string>
+    <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
     <string name="kg_failed_attempts_now_wiping" product="default">
        You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
        The phone will now be reset to factory default.
@@ -4527,6 +4717,14 @@
     </string>
     <!-- Message shown in dialog when user is almost at the limit where they will be
     locked out and may have to enter an alternate username/password to unlock the phone -->
+    <string name="kg_failed_attempts_almost_at_login" product="tv">
+       You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
+       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       you will be asked to unlock your TV using an email account.\n\n
+       Try again in <xliff:g id="number">%d</xliff:g> seconds.
+    </string>
+    <!-- Message shown in dialog when user is almost at the limit where they will be
+    locked out and may have to enter an alternate username/password to unlock the phone -->
     <string name="kg_failed_attempts_almost_at_login" product="default">
        You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
        After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index c4a949f..4b38ad3 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -223,7 +223,28 @@
     </family>
     <family>
         <fileset>
-            <file>NotoSansCherokee-Regular.ttf</file>
+            <file>NotoSansThaana-Regular.ttf</file>
+            <file>NotoSansThaana-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansBalinese-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansBatak-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansBuginese-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansBuhid-Regular.ttf</file>
         </fileset>
     </family>
     <family>
@@ -233,6 +254,66 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansCherokee-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansHanunoo-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansJavanese-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansLepcha-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansLimbu-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansMeeteiMayek-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansOlChiki-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansRejang-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansSaurashtra-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansSundanese-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansSylotiNagri-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansTagbanwa-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansYi-Regular.ttf</file>
         </fileset>
     </family>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 09055c6..4493554 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -220,12 +220,61 @@
         <font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font>
     </family>
     <family>
-        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
     </family>
     <family lang="zh-Hans">
diff --git a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_back.png
deleted file mode 100644
index f340a62..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_back.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_fore.png
deleted file mode 100644
index 2a4e595..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_fore.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_shadow.png
deleted file mode 100644
index f3a3120..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_shadow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_back.png
deleted file mode 100644
index c40b37c..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_back.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_fore.png
deleted file mode 100644
index aae684b..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_fore.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_shadow.png
deleted file mode 100644
index 61a0da9..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_shadow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/thumb.png
deleted file mode 100644
index e21a421..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/thumb.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_6/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/land_back.png
new file mode 100644
index 0000000..06695f5
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/land_back.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_6/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/land_fore.png
new file mode 100644
index 0000000..9fe5409
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_6/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/land_shadow.png
new file mode 100644
index 0000000..99f826f
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_6/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/port_back.png
new file mode 100644
index 0000000..6e1aec6
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/port_back.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_6/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/port_fore.png
new file mode 100644
index 0000000..53ec73a
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_6/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/port_shadow.png
new file mode 100644
index 0000000..66149c6
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_6/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/thumb.png
new file mode 100644
index 0000000..bc1f492
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_6/thumb.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_9/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/land_back.png
new file mode 100644
index 0000000..fdbc52c
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/land_back.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_9/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/land_fore.png
new file mode 100644
index 0000000..76fc78e
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_9/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/land_shadow.png
new file mode 100644
index 0000000..d40758f
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_9/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/port_back.png
new file mode 100644
index 0000000..fd6f88f
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/port_back.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_9/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/port_fore.png
new file mode 100644
index 0000000..328ceef
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_9/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/port_shadow.png
new file mode 100644
index 0000000..13eba2f
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_9/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/thumb.png
new file mode 100644
index 0000000..bb52e6c
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art-resources/nexus_9/thumb.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_back.png
deleted file mode 100644
index f525e8e..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_back.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_fore.png
deleted file mode 100644
index e26bfe1..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_fore.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_shadow.png
deleted file mode 100644
index ea26b73..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_shadow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_back.png
deleted file mode 100644
index ed4ad0c..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_back.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_fore.png
deleted file mode 100644
index 74bd077..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_fore.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_shadow.png
deleted file mode 100644
index bb4bec8..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_shadow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/thumb.png
deleted file mode 100644
index 8b9a3d9..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/nexus_s/thumb.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/xoom/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_back.png
deleted file mode 100644
index e1eb075..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/xoom/land_back.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/xoom/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_fore.png
deleted file mode 100644
index 15e5f50..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/xoom/land_fore.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/xoom/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_shadow.png
deleted file mode 100644
index 885508a..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/xoom/land_shadow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/xoom/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_back.png
deleted file mode 100644
index 290ca35..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/xoom/port_back.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/xoom/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_fore.png
deleted file mode 100644
index 8b3dca3..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/xoom/port_fore.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/xoom/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_shadow.png
deleted file mode 100644
index 895b75e..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/xoom/port_shadow.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art-resources/xoom/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/thumb.png
deleted file mode 100644
index 8fd08a4..0000000
--- a/docs/html/distribute/tools/promote/device-art-resources/xoom/thumb.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art.jd b/docs/html/distribute/tools/promote/device-art.jd
index 1736060..3902b30 100644
--- a/docs/html/distribute/tools/promote/device-art.jd
+++ b/docs/html/distribute/tools/promote/device-art.jd
@@ -66,7 +66,7 @@
   }
 
   .device-list {
-    padding: 0;
+    padding: 1em 0 0 0;
     margin: 0;
   }
 
@@ -187,6 +187,19 @@
       portSize: [1080,1920],
     },
     {
+      id: 'nexus_6',
+      title: 'Nexus 6',
+      url: 'http://www.google.com/nexus/6/',
+      physicalSize: 6,
+      physicalHeight: 6.27,
+      density: '560DPI',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [489,327],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [327,489],
+      portSize: [1440, 2560],
+    },
+    {
       id: 'nexus_7',
       title: 'Nexus 7',
       url: 'http://www.google.com/nexus/7/',
@@ -201,6 +214,20 @@
       portSize: [800,1280]
     },
     {
+      id: 'nexus_9',
+      title: 'Nexus 9',
+      url: 'http://www.google.com/nexus/9/',
+      physicalSize: 9,
+      physicalHeight: 8.98,
+      actualResolution: [1536,2048],
+      density: 'XHDPI',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [514,350],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [348,514],
+      portSize: [1536,2048],
+    },
+    {
       id: 'nexus_10',
       title: 'Nexus 10',
       url: 'http://www.google.com/nexus/10/',
@@ -212,19 +239,6 @@
       landOffset: [227,217],
       portRes: ['shadow', 'back', 'fore'],
       portOffset: [217,223],
-      portSize: [800,1280]
-    },
-    {
-      id: 'xoom',
-      title: 'Motorola XOOM',
-      url: 'http://www.google.com/phone/detail/motorola-xoom',
-      physicalSize: 10,
-      physicalHeight: 6.61,
-      density: 'MDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [218,191],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [199,200],
       portSize: [800,1280],
       archived: true
     },
@@ -256,34 +270,6 @@
       portSize: [768,1280],
       archived: true
     },
-    {
-      id: 'galaxy_nexus',
-      title: 'Galaxy Nexus',
-      url: 'http://www.android.com/devices/detail/galaxy-nexus',
-      physicalSize: 4.65,
-      physicalHeight: 5.33,
-      density: 'XHDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [371,199],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [216,353],
-      portSize: [720,1280],
-      archived: true
-    },
-    {
-      id: 'nexus_s',
-      title: 'Nexus S',
-      url: 'http://www.google.com/phone/detail/nexus-s',
-      physicalSize: 4.0,
-      physicalHeight: 4.88,
-      density: 'HDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [247,135],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [134,247],
-      portSize: [480,800],
-      archived: true
-    }
   ];
 
   DEVICES = DEVICES.sort(function(x, y) { return x.physicalSize - y.physicalSize; });
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index ec88efc..4afdf132 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -77,6 +77,17 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 21.1.1</a> <em>(November 2014)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Fixed multidex script issues.</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Build Tools, Revision 21.1</a> <em>(October 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index f206e56..33f6564 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -453,7 +453,8 @@
                             && !mTouchAboveFalsingThreshold;
 
                     boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
-                            && !falsingDetected && (childSwipedFastEnough || childSwipedFarEnough);
+                            && !falsingDetected && (childSwipedFastEnough || childSwipedFarEnough)
+                            && ev.getActionMasked() == MotionEvent.ACTION_UP;
 
                     if (dismissChild) {
                         // flingadingy
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 b531c681..9d7d310 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -523,7 +523,8 @@
             case MotionEvent.ACTION_UP:
                 trackMovement(event);
                 if (mQsTracking) {
-                    flingQsWithCurrentVelocity();
+                    flingQsWithCurrentVelocity(
+                            event.getActionMasked() == MotionEvent.ACTION_CANCEL);
                     mQsTracking = false;
                 }
                 mIntercepting = false;
@@ -558,9 +559,9 @@
         super.requestDisallowInterceptTouchEvent(disallowIntercept);
     }
 
-    private void flingQsWithCurrentVelocity() {
+    private void flingQsWithCurrentVelocity(boolean isCancelMotionEvent) {
         float vel = getCurrentVelocity();
-        flingSettings(vel, flingExpandsQs(vel));
+        flingSettings(vel, flingExpandsQs(vel) && !isCancelMotionEvent);
     }
 
     private boolean flingExpandsQs(float vel) {
@@ -729,7 +730,8 @@
                 float fraction = getQsExpansionFraction();
                 if ((fraction != 0f || y >= mInitialTouchY)
                         && (fraction != 1f || y <= mInitialTouchY)) {
-                    flingQsWithCurrentVelocity();
+                    flingQsWithCurrentVelocity(
+                            event.getActionMasked() == MotionEvent.ACTION_CANCEL);
                 } else {
                     mScrollYOverride = -1;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index c706ef0..47ce603 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -330,7 +330,8 @@
                         vectorVel = (float) Math.hypot(
                                 mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
                     }
-                    boolean expand = flingExpands(vel, vectorVel);
+                    boolean expand = flingExpands(vel, vectorVel)
+                            || event.getActionMasked() == MotionEvent.ACTION_CANCEL;
                     onTrackingStopped(expand);
                     DozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
                             mStatusBar.isFalsingThresholdNeeded(),
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index e92ea72d..c03bb58 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.pm.UserInfo;
@@ -243,11 +245,13 @@
     }
 
 
-    private String getLockPatternFilename(int userId) {
+    @VisibleForTesting
+    String getLockPatternFilename(int userId) {
         return getLockCredentialFilePathForUser(userId, LOCK_PATTERN_FILE);
     }
 
-    private String getLockPasswordFilename(int userId) {
+    @VisibleForTesting
+    String getLockPasswordFilename(int userId) {
         return getLockCredentialFilePathForUser(userId, LOCK_PASSWORD_FILE);
     }
 
@@ -310,6 +314,15 @@
         }
     }
 
+    @VisibleForTesting
+    void closeDatabase() {
+        mOpenHelper.close();
+    }
+
+    @VisibleForTesting
+    void clearCache() {
+        mCache.clear();
+    }
 
     public interface Callback {
         void initialize(SQLiteDatabase db);
@@ -455,6 +468,10 @@
             mVersion++;
         }
 
+        synchronized void clear() {
+            mCache.clear();
+            mVersion++;
+        }
 
         private static final class CacheKey {
             static final int TYPE_KEY_VALUE = 0;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 1a0e45e..c12cadb 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -21,6 +21,7 @@
 import android.os.Trace;
 
 import com.android.internal.app.ResolverActivity;
+import com.android.internal.content.ReferrerIntent;
 import com.android.internal.util.XmlUtils;
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
@@ -128,7 +129,7 @@
     final int requestCode;  // code given by requester (resultTo)
     ArrayList<ResultInfo> results; // pending ActivityResult objs we have received
     HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
-    ArrayList<Intent> newIntents; // any pending new intents for single-top mode
+    ArrayList<ReferrerIntent> newIntents; // any pending new intents for single-top mode
     ActivityOptions pendingOptions; // most recently given options
     ActivityOptions returningOptions; // options that are coming back via convertToTranslucent
     HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
@@ -629,9 +630,9 @@
         }
     }
 
-    void addNewIntentLocked(Intent intent) {
+    void addNewIntentLocked(ReferrerIntent intent) {
         if (newIntents == null) {
-            newIntents = new ArrayList<Intent>();
+            newIntents = new ArrayList<>();
         }
         newIntents.add(intent);
     }
@@ -640,7 +641,7 @@
      * Deliver a new Intent to an existing activity, so that its onNewIntent()
      * method will be called at the proper time.
      */
-    final void deliverNewIntentLocked(int callingUid, Intent intent) {
+    final void deliverNewIntentLocked(int callingUid, Intent intent, String referrer) {
         // The activity now gets access to the data associated with this Intent.
         service.grantUriPermissionFromIntentLocked(callingUid, packageName,
                 intent, getUriPermissionsLocked(), userId);
@@ -649,14 +650,14 @@
         // device is sleeping, then all activities are stopped, so in that
         // case we will deliver it if this is the current top activity on its
         // stack.
+        final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
         boolean unsent = true;
         if ((state == ActivityState.RESUMED || (service.isSleeping()
                         && task.stack.topRunningActivityLocked(null) == this))
                 && app != null && app.thread != null) {
             try {
-                ArrayList<Intent> ar = new ArrayList<Intent>();
-                intent = new Intent(intent);
-                ar.add(intent);
+                ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
+                ar.add(rintent);
                 app.thread.scheduleNewIntent(ar, appToken);
                 unsent = false;
             } catch (RemoteException e) {
@@ -668,7 +669,7 @@
             }
         }
         if (unsent) {
-            addNewIntentLocked(new Intent(intent));
+            addNewIntentLocked(rintent);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index b955011..cfcab68 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -44,6 +44,7 @@
 
 import android.util.ArraySet;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
@@ -2953,7 +2954,8 @@
                     parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
                     parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
                     (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
-                parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent);
+                parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent,
+                        srec.packageName);
             } else {
                 try {
                     ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
@@ -3773,7 +3775,7 @@
     private boolean relaunchActivityLocked(ActivityRecord r,
             int changes, boolean andResume) {
         List<ResultInfo> results = null;
-        List<Intent> newIntents = null;
+        List<ReferrerIntent> newIntents = null;
         if (andResume) {
             results = r.results;
             newIntents = r.newIntents;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 079df7d..099151f 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -97,6 +97,7 @@
 import android.view.Surface;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.widget.LockPatternUtils;
@@ -1101,7 +1102,7 @@
                 throw new RemoteException();
             }
             List<ResultInfo> results = null;
-            List<Intent> newIntents = null;
+            List<ReferrerIntent> newIntents = null;
             if (andResume) {
                 results = r.results;
                 newIntents = r.newIntents;
@@ -1155,9 +1156,9 @@
             app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                     System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
-                    r.compat, r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState,
-                    results, newIntents, !andResume, mService.isNextTransitionForward(),
-                    profilerInfo);
+                    r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
+                    r.icicle, r.persistentState, results, newIntents, !andResume,
+                    mService.isNextTransitionForward(), profilerInfo);
 
             if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
                 // This may be a heavy-weight process!  Note that the package
@@ -1896,7 +1897,7 @@
                             }
                             ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
                                     r, top.task);
-                            top.deliverNewIntentLocked(callingUid, r.intent);
+                            top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                         } else {
                             // A special case: we need to
                             // start the activity because it is not currently
@@ -1922,7 +1923,8 @@
                             if (intentActivity.frontOfTask) {
                                 intentActivity.task.setIntent(r);
                             }
-                            intentActivity.deliverNewIntentLocked(callingUid, r.intent);
+                            intentActivity.deliverNewIntentLocked(callingUid, r.intent,
+                                    r.launchedFromPackage);
                         } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
                             // In this case we are launching the root activity
                             // of the task, but with a different intent.  We
@@ -1995,7 +1997,7 @@
                                 // is the case, so this is it!
                                 return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                             }
-                            top.deliverNewIntentLocked(callingUid, r.intent);
+                            top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                             return ActivityManager.START_DELIVERED_TO_TOP;
                         }
                     }
@@ -2071,7 +2073,7 @@
                 keepCurTransition = true;
                 if (top != null) {
                     ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                    top.deliverNewIntentLocked(callingUid, r.intent);
+                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                     // For paranoia, make sure we have correctly
                     // resumed the top activity.
                     targetStack.mLastPausedActivity = null;
@@ -2092,7 +2094,7 @@
                     task.moveActivityToFrontLocked(top);
                     ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
                     top.updateOptionsLocked(options);
-                    top.deliverNewIntentLocked(callingUid, r.intent);
+                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                     targetStack.mLastPausedActivity = null;
                     if (doResume) {
                         targetStack.resumeTopActivityLocked(null);
@@ -2132,7 +2134,7 @@
                         // is the case, so this is it!
                         return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                     }
-                    top.deliverNewIntentLocked(callingUid, r.intent);
+                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                     return ActivityManager.START_DELIVERED_TO_TOP;
                 }
             }
diff --git a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
index 24fd155..0fb5732 100644
--- a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
+++ b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
@@ -18,6 +18,7 @@
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
+import android.app.AlarmManager.AlarmClockInfo;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -63,8 +64,10 @@
     private final Calendar mCalendar = Calendar.getInstance();
     private final Context mContext = this;
     private final ArraySet<Integer> mDays = new ArraySet<Integer>();
+    private final ArraySet<Long> mFiredAlarms = new ArraySet<Long>();
 
     private boolean mConnected;
+    private NextAlarmTracker mTracker;
     private int mDowntimeMode;
     private ZenModeConfig mConfig;
     private Callback mCallback;
@@ -77,6 +80,7 @@
         pw.println("    DowntimeConditionProvider:");
         pw.print("      mConnected="); pw.println(mConnected);
         pw.print("      mDowntimeMode="); pw.println(Global.zenModeToString(mDowntimeMode));
+        pw.print("      mFiredAlarms="); pw.println(mFiredAlarms);
     }
 
     public void attachBase(Context base) {
@@ -101,12 +105,15 @@
         filter.addAction(Intent.ACTION_TIME_CHANGED);
         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
         mContext.registerReceiver(mReceiver, filter);
+        mTracker = mCallback.getNextAlarmTracker();
+        mTracker.addCallback(mTrackerCallback);
         init();
     }
 
     @Override
     public void onDestroy() {
         if (DEBUG) Slog.d(TAG, "onDestroy");
+        mTracker.removeCallback(mTrackerCallback);
         mConnected = false;
     }
 
@@ -183,35 +190,52 @@
         }
     }
 
-    private int computeDowntimeMode(long time) {
-        if (mConfig == null || mDays.size() == 0) return Global.ZEN_MODE_OFF;
+    private boolean isInDowntime(long time) {
+        if (mConfig == null || mDays.size() == 0) return false;
         final long start = getTime(time, mConfig.sleepStartHour, mConfig.sleepStartMinute);
         long end = getTime(time, mConfig.sleepEndHour, mConfig.sleepEndMinute);
-        if (start == end) return Global.ZEN_MODE_OFF;
+        if (start == end) return false;
         if (end < start) {
             end = addDays(end, 1);
         }
-        final boolean inDowntime = isInDowntime(-1, time, start, end)
-                || isInDowntime(0, time, start, end);
-        return inDowntime ? (mConfig.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
-                : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) : Global.ZEN_MODE_OFF;
+        final boolean orAlarm = mConfig.sleepNone;
+        return isInDowntime(-1, time, start, end, orAlarm)
+                || isInDowntime(0, time, start, end, orAlarm);
     }
 
-    private boolean isInDowntime(int daysOffset, long time, long start, long end) {
+    private boolean isInDowntime(int daysOffset, long time, long start, long end, boolean orAlarm) {
         final int n = Calendar.SATURDAY;
         final int day = ((getDayOfWeek(time) - 1) + (daysOffset % n) + n) % n + 1;
         start = addDays(start, daysOffset);
         end = addDays(end, daysOffset);
+        if (orAlarm) {
+            end = findFiredAlarm(start, end);
+        }
         return mDays.contains(day) && time >= start && time < end;
     }
 
+    private long findFiredAlarm(long start, long end) {
+        final int N = mFiredAlarms.size();
+        for (int i = 0; i < N; i++) {
+            final long firedAlarm = mFiredAlarms.valueAt(i);
+            if (firedAlarm > start && firedAlarm < end) {
+                return firedAlarm;
+            }
+        }
+        return end;
+    }
+
     private void reevaluateDowntime() {
-        final int downtimeMode = computeDowntimeMode(System.currentTimeMillis());
+        final long now = System.currentTimeMillis();
+        final boolean inDowntimeNow = isInDowntime(now);
+        final int downtimeMode = inDowntimeNow ? (mConfig.sleepNone
+                ? Global.ZEN_MODE_NO_INTERRUPTIONS : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+                : Global.ZEN_MODE_OFF;
         if (DEBUG) Slog.d(TAG, "downtimeMode=" + downtimeMode);
         if (downtimeMode == mDowntimeMode) return;
         mDowntimeMode = downtimeMode;
         Slog.i(TAG, (isInDowntime() ? "Entering" : "Exiting" ) + " downtime");
-        ZenLog.traceDowntime(mDowntimeMode, getDayOfWeek(System.currentTimeMillis()), mDays);
+        ZenLog.traceDowntime(mDowntimeMode, getDayOfWeek(now), mDays);
         fireDowntimeChanged();
     }
 
@@ -266,8 +290,8 @@
                 PendingIntent.FLAG_UPDATE_CURRENT);
         alarms.cancel(pendingIntent);
         if (mConfig.sleepMode != null) {
-            if (DEBUG) Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future, now=%s",
-                    action, ts(time), time - now, ts(now)));
+            if (DEBUG) Slog.d(TAG, String.format("Scheduling %s for %s, in %s, now=%s",
+                    action, ts(time), NextAlarmTracker.formatDuration(time - now), ts(now)));
             alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
         }
     }
@@ -276,6 +300,30 @@
         return new Date(time) + " (" + time + ")";
     }
 
+    private void onEvaluateNextAlarm(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
+        if (!booted) return;  // we don't know yet
+        if (nextAlarm == null) return;  // not fireable
+        if (DEBUG) Slog.d(TAG, "onEvaluateNextAlarm " + mTracker.formatAlarmDebug(nextAlarm));
+        if (System.currentTimeMillis() > wakeupTime) {
+            if (DEBUG) Slog.d(TAG, "Alarm fired: " + mTracker.formatAlarmDebug(wakeupTime));
+            trimFiredAlarms();
+            mFiredAlarms.add(wakeupTime);
+        }
+        reevaluateDowntime();
+    }
+
+    private void trimFiredAlarms() {
+        // remove fired alarms over 2 days old
+        final long keepAfter = System.currentTimeMillis() - 2 * 24 * 60 * 60 * 1000;
+        final int N = mFiredAlarms.size();
+        for (int i = N - 1; i >= 0; i--) {
+            final long firedAlarm = mFiredAlarms.valueAt(i);
+            if (firedAlarm < keepAfter) {
+                mFiredAlarms.removeAt(i);
+            }
+        }
+    }
+
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -296,6 +344,13 @@
         }
     };
 
+    private final NextAlarmTracker.Callback mTrackerCallback = new NextAlarmTracker.Callback() {
+        @Override
+        public void onEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
+            DowntimeConditionProvider.this.onEvaluateNextAlarm(nextAlarm, wakeupTime, booted);
+        }
+    };
+
     public interface Callback {
         void onDowntimeChanged(int downtimeMode);
         NextAlarmTracker getNextAlarmTracker();
diff --git a/services/core/java/com/android/server/notification/NextAlarmTracker.java b/services/core/java/com/android/server/notification/NextAlarmTracker.java
index d197afd..234f545 100644
--- a/services/core/java/com/android/server/notification/NextAlarmTracker.java
+++ b/services/core/java/com/android/server/notification/NextAlarmTracker.java
@@ -176,7 +176,7 @@
         return true;
     }
 
-    private static String formatDuration(long millis) {
+    public static String formatDuration(long millis) {
         final StringBuilder sb = new StringBuilder();
         TimeUtils.formatDuration(millis, sb);
         return sb.toString();
@@ -196,7 +196,7 @@
         return DateFormat.format(pattern, time).toString();
     }
 
-    private String formatAlarmDebug(AlarmClockInfo alarm) {
+    public String formatAlarmDebug(AlarmClockInfo alarm) {
         return formatAlarmDebug(alarm != null ? alarm.getTriggerTime() : 0);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
new file mode 100644
index 0000000..bf0e75d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.UserInfo;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.FileUtils;
+import android.os.UserManager;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+public class LockSettingsStorageTests extends AndroidTestCase {
+    LockSettingsStorage mStorage;
+    File mStorageDir;
+
+    private File mDb;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mStorageDir = new File(getContext().getFilesDir(), "locksettings");
+        mDb = getContext().getDatabasePath("locksettings.db");
+
+        assertTrue(mStorageDir.exists() || mStorageDir.mkdirs());
+        assertTrue(FileUtils.deleteContents(mStorageDir));
+        assertTrue(!mDb.exists() || mDb.delete());
+
+        final Context ctx = getContext();
+        setContext(new ContextWrapper(ctx) {
+            @Override
+            public Object getSystemService(String name) {
+                if (USER_SERVICE.equals(name)) {
+                    return new UserManager(ctx, null) {
+                        @Override
+                        public UserInfo getProfileParent(int userHandle) {
+                            if (userHandle == 2) {
+                                // User 2 is a profile of user 1.
+                                return new UserInfo(1, "name", 0);
+                            }
+                            if (userHandle == 3) {
+                                // User 3 is a profile of user 0.
+                                return new UserInfo(0, "name", 0);
+                            }
+                            return null;
+                        }
+                    };
+                }
+                return super.getSystemService(name);
+            }
+        });
+
+        mStorage = new LockSettingsStorage(getContext(), new LockSettingsStorage.Callback() {
+            @Override
+            public void initialize(SQLiteDatabase db) {
+                mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
+            }
+        }) {
+            @Override
+            String getLockPatternFilename(int userId) {
+                return new File(mStorageDir,
+                        super.getLockPatternFilename(userId).replace('/', '-')).getAbsolutePath();
+            }
+
+            @Override
+            String getLockPasswordFilename(int userId) {
+                return new File(mStorageDir,
+                        super.getLockPasswordFilename(userId).replace('/', '-')).getAbsolutePath();
+            }
+        };
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mStorage.closeDatabase();
+    }
+
+    public void testKeyValue_InitializeWorked() {
+        assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
+        mStorage.clearCache();
+        assertEquals("initialValue", mStorage.readKeyValue("initializedKey", "default", 0));
+    }
+
+    public void testKeyValue_WriteThenRead() {
+        mStorage.writeKeyValue("key", "value", 0);
+        assertEquals("value", mStorage.readKeyValue("key", "default", 0));
+        mStorage.clearCache();
+        assertEquals("value", mStorage.readKeyValue("key", "default", 0));
+    }
+
+    public void testKeyValue_DefaultValue() {
+        assertEquals("default", mStorage.readKeyValue("unititialized key", "default", 0));
+        assertEquals("default2", mStorage.readKeyValue("unititialized key", "default2", 0));
+    }
+
+    public void testKeyValue_Concurrency() {
+        final Object monitor = new Object();
+        List<Thread> threads = new ArrayList<>();
+        for (int i = 0; i < 100; i++) {
+            final int threadId = i;
+            threads.add(new Thread() {
+                @Override
+                public void run() {
+                    synchronized (monitor) {
+                        try {
+                            monitor.wait();
+                        } catch (InterruptedException e) {
+                            return;
+                        }
+                        mStorage.writeKeyValue("key", "1 from thread " + threadId, 0);
+                        mStorage.readKeyValue("key", "default", 0);
+                        mStorage.writeKeyValue("key", "2 from thread " + threadId, 0);
+                        mStorage.readKeyValue("key", "default", 0);
+                        mStorage.writeKeyValue("key", "3 from thread " + threadId, 0);
+                        mStorage.readKeyValue("key", "default", 0);
+                        mStorage.writeKeyValue("key", "4 from thread " + threadId, 0);
+                        mStorage.readKeyValue("key", "default", 0);
+                        mStorage.writeKeyValue("key", "5 from thread " + threadId, 0);
+                        mStorage.readKeyValue("key", "default", 0);
+                    }
+                }
+            });
+            threads.get(i).start();
+        }
+        mStorage.writeKeyValue("key", "initalValue", 0);
+        synchronized (monitor) {
+            monitor.notifyAll();
+        }
+        for (int i = 0; i < threads.size(); i++) {
+            try {
+                threads.get(i).join();
+            } catch (InterruptedException e) {
+            }
+        }
+        assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
+        mStorage.clearCache();
+        assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
+    }
+
+    public void testKeyValue_CacheStarvedWriter() {
+        final CountDownLatch latch = new CountDownLatch(1);
+        List<Thread> threads = new ArrayList<>();
+        for (int i = 0; i < 100; i++) {
+            final int threadId = i;
+            threads.add(new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        latch.await();
+                    } catch (InterruptedException e) {
+                        return;
+                    }
+                    if (threadId == 50) {
+                        mStorage.writeKeyValue("starvedWriterKey", "value", 0);
+                    } else {
+                        mStorage.readKeyValue("starvedWriterKey", "default", 0);
+                    }
+                }
+            });
+            threads.get(i).start();
+        }
+        latch.countDown();
+        for (int i = 0; i < threads.size(); i++) {
+            try {
+                threads.get(i).join();
+            } catch (InterruptedException e) {
+            }
+        }
+        String cached = mStorage.readKeyValue("key", "default", 0);
+        mStorage.clearCache();
+        String storage = mStorage.readKeyValue("key", "default", 0);
+        assertEquals("Cached value didn't match stored value", storage, cached);
+    }
+
+    public void testRemoveUser() {
+        mStorage.writeKeyValue("key", "value", 0);
+        mStorage.writePasswordHash(new byte[]{1}, 0);
+        mStorage.writePatternHash(new byte[]{2}, 0);
+
+        mStorage.writeKeyValue("key", "value", 1);
+        mStorage.writePasswordHash(new byte[]{1}, 1);
+        mStorage.writePatternHash(new byte[]{2}, 1);
+
+        mStorage.removeUser(0);
+
+        assertEquals("value", mStorage.readKeyValue("key", "default", 1));
+        assertEquals("default", mStorage.readKeyValue("key", "default", 0));
+        assertNotNull(mStorage.readPasswordHash(1));
+        assertNull(mStorage.readPasswordHash(0));
+        assertNotNull(mStorage.readPatternHash(1));
+        assertNull(mStorage.readPatternHash(0));
+    }
+
+    public void testPassword_Default() {
+        assertNull(mStorage.readPasswordHash(0));
+    }
+
+    public void testPassword_Write() {
+        mStorage.writePasswordHash("thepassword".getBytes(), 0);
+
+        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0));
+        mStorage.clearCache();
+        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0));
+    }
+
+    public void testPassword_WriteProfileWritesParent() {
+        mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
+        mStorage.writePasswordHash("profilepassword".getBytes(), 2);
+
+        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1));
+        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2));
+        mStorage.clearCache();
+        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1));
+        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2));
+    }
+
+    public void testPassword_WriteParentWritesProfile() {
+        mStorage.writePasswordHash("profilepassword".getBytes(), 2);
+        mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
+
+        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1));
+        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2));
+        mStorage.clearCache();
+        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1));
+        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2));
+    }
+
+    public void testPattern_Default() {
+        assertNull(mStorage.readPasswordHash(0));
+    }
+
+    public void testPattern_Write() {
+        mStorage.writePatternHash("thepattern".getBytes(), 0);
+
+        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0));
+        mStorage.clearCache();
+        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0));
+    }
+
+    public void testPattern_WriteProfileWritesParent() {
+        mStorage.writePatternHash("parentpatternn".getBytes(), 1);
+        mStorage.writePatternHash("profilepattern".getBytes(), 2);
+
+        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1));
+        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2));
+        mStorage.clearCache();
+        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1));
+        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2));
+    }
+
+    public void testPattern_WriteParentWritesProfile() {
+        mStorage.writePatternHash("profilepattern".getBytes(), 2);
+        mStorage.writePatternHash("parentpatternn".getBytes(), 1);
+
+        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1));
+        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2));
+        mStorage.clearCache();
+        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1));
+        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2));
+    }
+
+    public void testPrefetch() {
+        mStorage.writeKeyValue("key", "toBeFetched", 0);
+        mStorage.writePatternHash("pattern".getBytes(), 0);
+        mStorage.writePasswordHash("password".getBytes(), 0);
+
+        mStorage.clearCache();
+        mStorage.prefetchUser(0);
+
+        assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
+        assertArrayEquals("pattern".getBytes(), mStorage.readPatternHash(0));
+        assertArrayEquals("password".getBytes(), mStorage.readPasswordHash(0));
+    }
+
+    public void testFileLocation_Owner() {
+        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
+
+        assertEquals("/data/system/gesture.key", storage.getLockPatternFilename(0));
+        assertEquals("/data/system/password.key", storage.getLockPasswordFilename(0));
+    }
+
+    public void testFileLocation_SecondaryUser() {
+        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
+
+        assertEquals("/data/system/users/1/gesture.key", storage.getLockPatternFilename(1));
+        assertEquals("/data/system/users/1/password.key", storage.getLockPasswordFilename(1));
+    }
+
+    public void testFileLocation_ProfileToSecondary() {
+        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
+
+        assertEquals("/data/system/users/1/gesture.key", storage.getLockPatternFilename(2));
+        assertEquals("/data/system/users/1/password.key", storage.getLockPasswordFilename(2));
+    }
+
+    public void testFileLocation_ProfileToOwner() {
+        LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
+
+        assertEquals("/data/system/gesture.key", storage.getLockPatternFilename(3));
+        assertEquals("/data/system/password.key", storage.getLockPasswordFilename(3));
+    }
+
+    private static void assertArrayEquals(byte[] expected, byte[] actual) {
+        if (!Arrays.equals(expected, actual)) {
+            fail("expected:<" + Arrays.toString(expected) +
+                    "> but was:<" + Arrays.toString(actual) + ">");
+        }
+    }
+}
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 94874c8..b065b88c 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -140,6 +140,8 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        Log.i(TAG, "Referrer: " + getReferrer());
+
         mAm = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
         if (savedInstanceState != null) {
             mOverrideConfig = savedInstanceState.getParcelable(KEY_CONFIGURATION);
diff --git a/tools/layoutlib/bridge/resources/icons/shadow-b.png b/tools/layoutlib/bridge/resources/icons/shadow-b.png
new file mode 100644
index 0000000..68f4f4b
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow-b.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow-bl.png b/tools/layoutlib/bridge/resources/icons/shadow-bl.png
new file mode 100644
index 0000000..ee7dbe8
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow-bl.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow-br.png b/tools/layoutlib/bridge/resources/icons/shadow-br.png
new file mode 100644
index 0000000..c45ad77
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow-br.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow-l.png b/tools/layoutlib/bridge/resources/icons/shadow-l.png
new file mode 100644
index 0000000..77d0bd0
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow-l.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow-r.png b/tools/layoutlib/bridge/resources/icons/shadow-r.png
new file mode 100644
index 0000000..4af7a33
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow-r.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow-tl.png b/tools/layoutlib/bridge/resources/icons/shadow-tl.png
new file mode 100644
index 0000000..424fb36
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow-tl.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow-tr.png b/tools/layoutlib/bridge/resources/icons/shadow-tr.png
new file mode 100644
index 0000000..1fd0c772
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow-tr.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow2-b.png b/tools/layoutlib/bridge/resources/icons/shadow2-b.png
new file mode 100644
index 0000000..963973e
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow2-b.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow2-bl.png b/tools/layoutlib/bridge/resources/icons/shadow2-bl.png
new file mode 100644
index 0000000..7612487
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow2-bl.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow2-br.png b/tools/layoutlib/bridge/resources/icons/shadow2-br.png
new file mode 100644
index 0000000..8e20252
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow2-br.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow2-l.png b/tools/layoutlib/bridge/resources/icons/shadow2-l.png
new file mode 100644
index 0000000..2db18a0
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow2-l.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow2-r.png b/tools/layoutlib/bridge/resources/icons/shadow2-r.png
new file mode 100644
index 0000000..8e026f1
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow2-r.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow2-tl.png b/tools/layoutlib/bridge/resources/icons/shadow2-tl.png
new file mode 100644
index 0000000..a8045ed
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow2-tl.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/icons/shadow2-tr.png b/tools/layoutlib/bridge/resources/icons/shadow2-tr.png
new file mode 100644
index 0000000..590373c
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/icons/shadow2-tr.png
Binary files differ
diff --git a/tools/layoutlib/bridge/src/android/animation/AnimatorInflater_Delegate.java b/tools/layoutlib/bridge/src/android/animation/AnimatorInflater_Delegate.java
index d8a6ffc..4475fa4 100644
--- a/tools/layoutlib/bridge/src/android/animation/AnimatorInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/animation/AnimatorInflater_Delegate.java
@@ -54,6 +54,6 @@
     /*package*/ static ValueAnimator loadAnimator(Resources res, Theme theme,
             AttributeSet attrs, ValueAnimator anim, float pathErrorScale)
             throws NotFoundException {
-        return anim;
+        return AnimatorInflater.loadAnimator_Original(res, theme, attrs, anim, pathErrorScale);
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index f4282ad..8d24d38 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -141,7 +141,6 @@
      * Creates and returns a {@link Bitmap} initialized with the given stream content.
      *
      * @param input the stream from which to read the bitmap content
-     * @param createFlags
      * @param density the density associated with the bitmap
      *
      * @see Bitmap#isPremultiplied()
@@ -166,8 +165,7 @@
      * @see Bitmap#isMutable()
      * @see Bitmap#getDensity()
      */
-    public static Bitmap createBitmap(BufferedImage image, boolean isMutable,
-            Density density) throws IOException {
+    public static Bitmap createBitmap(BufferedImage image, boolean isMutable, Density density) {
         return createBitmap(image, getPremultipliedBitmapCreateFlags(isMutable), density);
     }
 
@@ -175,7 +173,6 @@
      * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
      *
      * @param image the bitmap content
-     * @param createFlags
      * @param density the density associated with the bitmap
      *
      * @see Bitmap#isPremultiplied()
@@ -183,7 +180,7 @@
      * @see Bitmap#getDensity()
      */
     public static Bitmap createBitmap(BufferedImage image, Set<BitmapCreateFlags> createFlags,
-            Density density) throws IOException {
+            Density density) {
         // create a delegate with the given image.
         Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
 
diff --git a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
new file mode 100644
index 0000000..6c949d9
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
@@ -0,0 +1,72 @@
+/*
+ * 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 com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of {@link RenderNode}
+ * <p/>
+ * Through the layoutlib_create tool, some native methods of RenderNode have been replaced by calls
+ * to methods of the same name in this delegate class.
+ *
+ * @see DelegateManager
+ */
+public class RenderNode_Delegate {
+
+
+    // ---- delegate manager ----
+    private static final DelegateManager<RenderNode_Delegate> sManager =
+            new DelegateManager<RenderNode_Delegate>(RenderNode_Delegate.class);
+
+
+    private float mLift;
+    @SuppressWarnings("UnusedDeclaration")
+    private String mName;
+
+    @LayoutlibDelegate
+    /*package*/ static long nCreate(String name) {
+        RenderNode_Delegate renderNodeDelegate = new RenderNode_Delegate();
+        renderNodeDelegate.mName = name;
+        return sManager.addNewDelegate(renderNodeDelegate);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nDestroyRenderNode(long renderNode) {
+        sManager.removeJavaReferenceFor(renderNode);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetElevation(long renderNode, float lift) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mLift != lift) {
+            delegate.mLift = lift;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static float nGetElevation(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            return delegate.mLift;
+        }
+        return 0f;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
new file mode 100644
index 0000000..38846bd
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
@@ -0,0 +1,415 @@
+/*
+ * 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 com.android.annotations.NonNull;
+
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.imageio.ImageIO;
+
+public class ShadowPainter {
+
+    /**
+     * Adds a drop shadow to a semi-transparent image (of an arbitrary shape) and returns it as a
+     * new image. This method attempts to mimic the same visual characteristics as the rectangular
+     * shadow painting methods in this class, {@link #createRectangularDropShadow(java.awt.image.BufferedImage)}
+     * and {@link #createSmallRectangularDropShadow(java.awt.image.BufferedImage)}.
+     *
+     * @param source the source image
+     * @param shadowSize the size of the shadow, normally {@link #SHADOW_SIZE or {@link
+     * #SMALL_SHADOW_SIZE}}
+     *
+     * @return a new image with the shadow painted in
+     */
+    @NonNull
+    public static BufferedImage createDropShadow(BufferedImage source, int shadowSize) {
+        shadowSize /= 2; // make shadow size have the same meaning as in the other shadow paint methods in this class
+
+        return createDropShadow(source, shadowSize, 0.7f, 0);
+    }
+
+    /**
+     * Creates a drop shadow of a given image and returns a new image which shows the input image on
+     * top of its drop shadow.
+     * <p/>
+     * <b>NOTE: If the shape is rectangular and opaque, consider using {@link
+     * #drawRectangleShadow(Graphics2D, int, int, int, int)} instead.</b>
+     *
+     * @param source the source image to be shadowed
+     * @param shadowSize the size of the shadow in pixels
+     * @param shadowOpacity the opacity of the shadow, with 0=transparent and 1=opaque
+     * @param shadowRgb the RGB int to use for the shadow color
+     *
+     * @return a new image with the source image on top of its shadow
+     */
+    @SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"})  // Imported code
+    public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
+            float shadowOpacity, int shadowRgb) {
+
+        // This code is based on
+        //      http://www.jroller.com/gfx/entry/non_rectangular_shadow
+
+        BufferedImage image;
+        int width = source.getWidth();
+        int height = source.getHeight();
+        image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE,
+                BufferedImage.TYPE_INT_ARGB);
+
+        Graphics2D g2 = image.createGraphics();
+        g2.drawImage(image, shadowSize, shadowSize, null);
+
+        int dstWidth = image.getWidth();
+        int dstHeight = image.getHeight();
+
+        int left = (shadowSize - 1) >> 1;
+        int right = shadowSize - left;
+        int xStart = left;
+        int xStop = dstWidth - right;
+        int yStart = left;
+        int yStop = dstHeight - right;
+
+        shadowRgb &= 0x00FFFFFF;
+
+        int[] aHistory = new int[shadowSize];
+        int historyIdx;
+
+        int aSum;
+
+        int[] dataBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
+        int lastPixelOffset = right * dstWidth;
+        float sumDivider = shadowOpacity / shadowSize;
+
+        // horizontal pass
+        for (int y = 0, bufferOffset = 0; y < dstHeight; y++, bufferOffset = y * dstWidth) {
+            aSum = 0;
+            historyIdx = 0;
+            for (int x = 0; x < shadowSize; x++, bufferOffset++) {
+                int a = dataBuffer[bufferOffset] >>> 24;
+                aHistory[x] = a;
+                aSum += a;
+            }
+
+            bufferOffset -= right;
+
+            for (int x = xStart; x < xStop; x++, bufferOffset++) {
+                int a = (int) (aSum * sumDivider);
+                dataBuffer[bufferOffset] = a << 24 | shadowRgb;
+
+                // subtract the oldest pixel from the sum
+                aSum -= aHistory[historyIdx];
+
+                // get the latest pixel
+                a = dataBuffer[bufferOffset + right] >>> 24;
+                aHistory[historyIdx] = a;
+                aSum += a;
+
+                if (++historyIdx >= shadowSize) {
+                    historyIdx -= shadowSize;
+                }
+            }
+        }
+        // vertical pass
+        for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) {
+            aSum = 0;
+            historyIdx = 0;
+            for (int y = 0; y < shadowSize; y++, bufferOffset += dstWidth) {
+                int a = dataBuffer[bufferOffset] >>> 24;
+                aHistory[y] = a;
+                aSum += a;
+            }
+
+            bufferOffset -= lastPixelOffset;
+
+            for (int y = yStart; y < yStop; y++, bufferOffset += dstWidth) {
+                int a = (int) (aSum * sumDivider);
+                dataBuffer[bufferOffset] = a << 24 | shadowRgb;
+
+                // subtract the oldest pixel from the sum
+                aSum -= aHistory[historyIdx];
+
+                // get the latest pixel
+                a = dataBuffer[bufferOffset + lastPixelOffset] >>> 24;
+                aHistory[historyIdx] = a;
+                aSum += a;
+
+                if (++historyIdx >= shadowSize) {
+                    historyIdx -= shadowSize;
+                }
+            }
+        }
+
+        g2.drawImage(source, null, 0, 0);
+        g2.dispose();
+
+        return image;
+    }
+
+    /**
+     * Draws a rectangular drop shadow (of size {@link #SHADOW_SIZE} by {@link #SHADOW_SIZE} around
+     * the given source and returns a new image with both combined
+     *
+     * @param source the source image
+     *
+     * @return the source image with a drop shadow on the bottom and right
+     */
+    @SuppressWarnings("UnusedDeclaration")
+    public static BufferedImage createRectangularDropShadow(BufferedImage source) {
+        int type = source.getType();
+        if (type == BufferedImage.TYPE_CUSTOM) {
+            type = BufferedImage.TYPE_INT_ARGB;
+        }
+
+        int width = source.getWidth();
+        int height = source.getHeight();
+        BufferedImage image;
+        image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE, type);
+        Graphics2D g = image.createGraphics();
+        g.drawImage(source, 0, 0, null);
+        drawRectangleShadow(image, 0, 0, width, height);
+        g.dispose();
+
+        return image;
+    }
+
+    /**
+     * Draws a small rectangular drop shadow (of size {@link #SMALL_SHADOW_SIZE} by {@link
+     * #SMALL_SHADOW_SIZE} around the given source and returns a new image with both combined
+     *
+     * @param source the source image
+     *
+     * @return the source image with a drop shadow on the bottom and right
+     */
+    @SuppressWarnings("UnusedDeclaration")
+    public static BufferedImage createSmallRectangularDropShadow(BufferedImage source) {
+        int type = source.getType();
+        if (type == BufferedImage.TYPE_CUSTOM) {
+            type = BufferedImage.TYPE_INT_ARGB;
+        }
+
+        int width = source.getWidth();
+        int height = source.getHeight();
+
+        BufferedImage image;
+        image = new BufferedImage(width + SMALL_SHADOW_SIZE, height + SMALL_SHADOW_SIZE, type);
+
+        Graphics2D g = image.createGraphics();
+        g.drawImage(source, 0, 0, null);
+        drawSmallRectangleShadow(image, 0, 0, width, height);
+        g.dispose();
+
+        return image;
+    }
+
+    /**
+     * Draws a drop shadow for the given rectangle into the given context. It will not draw anything
+     * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow
+     * graphics. The size of the shadow is {@link #SHADOW_SIZE}.
+     *
+     * @param image the image to draw the shadow into
+     * @param x the left coordinate of the left hand side of the rectangle
+     * @param y the top coordinate of the top of the rectangle
+     * @param width the width of the rectangle
+     * @param height the height of the rectangle
+     */
+    public static void drawRectangleShadow(BufferedImage image,
+            int x, int y, int width, int height) {
+        Graphics2D gc = image.createGraphics();
+        try {
+            drawRectangleShadow(gc, x, y, width, height);
+        } finally {
+            gc.dispose();
+        }
+    }
+
+    /**
+     * Draws a small drop shadow for the given rectangle into the given context. It will not draw
+     * anything if the rectangle is smaller than a minimum determined by the assets used to draw the
+     * shadow graphics. The size of the shadow is {@link #SMALL_SHADOW_SIZE}.
+     *
+     * @param image the image to draw the shadow into
+     * @param x the left coordinate of the left hand side of the rectangle
+     * @param y the top coordinate of the top of the rectangle
+     * @param width the width of the rectangle
+     * @param height the height of the rectangle
+     */
+    public static void drawSmallRectangleShadow(BufferedImage image,
+            int x, int y, int width, int height) {
+        Graphics2D gc = image.createGraphics();
+        try {
+            drawSmallRectangleShadow(gc, x, y, width, height);
+        } finally {
+            gc.dispose();
+        }
+    }
+
+    /**
+     * The width and height of the drop shadow painted by
+     * {@link #drawRectangleShadow(Graphics2D, int, int, int, int)}
+     */
+    public static final int SHADOW_SIZE = 20; // DO NOT EDIT. This corresponds to bitmap graphics
+
+    /**
+     * The width and height of the drop shadow painted by
+     * {@link #drawSmallRectangleShadow(Graphics2D, int, int, int, int)}
+     */
+    public static final int SMALL_SHADOW_SIZE = 10; // DO NOT EDIT. Corresponds to bitmap graphics
+
+    /**
+     * Draws a drop shadow for the given rectangle into the given context. It will not draw anything
+     * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow
+     * graphics.
+     *
+     * @param gc the graphics context to draw into
+     * @param x the left coordinate of the left hand side of the rectangle
+     * @param y the top coordinate of the top of the rectangle
+     * @param width the width of the rectangle
+     * @param height the height of the rectangle
+     */
+    public static void drawRectangleShadow(Graphics2D gc, int x, int y, int width, int height) {
+        assert ShadowBottomLeft != null;
+        assert ShadowBottomRight.getWidth(null) == SHADOW_SIZE;
+        assert ShadowBottomRight.getHeight(null) == SHADOW_SIZE;
+
+        int blWidth = ShadowBottomLeft.getWidth(null);
+        int trHeight = ShadowTopRight.getHeight(null);
+        if (width < blWidth) {
+            return;
+        }
+        if (height < trHeight) {
+            return;
+        }
+
+        gc.drawImage(ShadowBottomLeft, x - ShadowBottomLeft.getWidth(null), y + height, null);
+        gc.drawImage(ShadowBottomRight, x + width, y + height, null);
+        gc.drawImage(ShadowTopRight, x + width, y, null);
+        gc.drawImage(ShadowTopLeft, x - ShadowTopLeft.getWidth(null), y, null);
+        gc.drawImage(ShadowBottom,
+                x, y + height, x + width, y + height + ShadowBottom.getHeight(null),
+                0, 0, ShadowBottom.getWidth(null), ShadowBottom.getHeight(null), null);
+        gc.drawImage(ShadowRight,
+                x + width, y + ShadowTopRight.getHeight(null), x + width + ShadowRight.getWidth(null), y + height,
+                0, 0, ShadowRight.getWidth(null), ShadowRight.getHeight(null), null);
+        gc.drawImage(ShadowLeft,
+                x - ShadowLeft.getWidth(null), y + ShadowTopLeft.getHeight(null), x, y + height,
+                0, 0, ShadowLeft.getWidth(null), ShadowLeft.getHeight(null), null);
+    }
+
+    /**
+     * Draws a small drop shadow for the given rectangle into the given context. It will not draw
+     * anything if the rectangle is smaller than a minimum determined by the assets used to draw the
+     * shadow graphics.
+     * <p/>
+     *
+     * @param gc the graphics context to draw into
+     * @param x the left coordinate of the left hand side of the rectangle
+     * @param y the top coordinate of the top of the rectangle
+     * @param width the width of the rectangle
+     * @param height the height of the rectangle
+     */
+    public static void drawSmallRectangleShadow(Graphics2D gc, int x, int y, int width,
+            int height) {
+        assert Shadow2BottomLeft != null;
+        assert Shadow2TopRight != null;
+        assert Shadow2BottomRight.getWidth(null) == SMALL_SHADOW_SIZE;
+        assert Shadow2BottomRight.getHeight(null) == SMALL_SHADOW_SIZE;
+
+        int blWidth = Shadow2BottomLeft.getWidth(null);
+        int trHeight = Shadow2TopRight.getHeight(null);
+        if (width < blWidth) {
+            return;
+        }
+        if (height < trHeight) {
+            return;
+        }
+
+        gc.drawImage(Shadow2BottomLeft, x - Shadow2BottomLeft.getWidth(null), y + height, null);
+        gc.drawImage(Shadow2BottomRight, x + width, y + height, null);
+        gc.drawImage(Shadow2TopRight, x + width, y, null);
+        gc.drawImage(Shadow2TopLeft, x - Shadow2TopLeft.getWidth(null), y, null);
+        gc.drawImage(Shadow2Bottom,
+                x, y + height, x + width, y + height + Shadow2Bottom.getHeight(null),
+                0, 0, Shadow2Bottom.getWidth(null), Shadow2Bottom.getHeight(null), null);
+        gc.drawImage(Shadow2Right,
+                x + width, y + Shadow2TopRight.getHeight(null), x + width + Shadow2Right.getWidth(null), y + height,
+                0, 0, Shadow2Right.getWidth(null), Shadow2Right.getHeight(null), null);
+        gc.drawImage(Shadow2Left,
+                x - Shadow2Left.getWidth(null), y + Shadow2TopLeft.getHeight(null), x, y + height,
+                0, 0, Shadow2Left.getWidth(null), Shadow2Left.getHeight(null), null);
+    }
+
+    private static Image loadIcon(String name) {
+        InputStream inputStream = ShadowPainter.class.getResourceAsStream(name);
+        if (inputStream == null) {
+            throw new RuntimeException("Unable to load image for shadow: " + name);
+        }
+        try {
+            return ImageIO.read(inputStream);
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to load image for shadow:" + name, e);
+        } finally {
+            try {
+                inputStream.close();
+            } catch (IOException e) {
+                // ignore.
+            }
+        }
+    }
+
+    // Shadow graphics. This was generated by creating a drop shadow in
+    // Gimp, using the parameters x offset=10, y offset=10, blur radius=10,
+    // (for the small drop shadows x offset=10, y offset=10, blur radius=10)
+    // color=black, and opacity=51. These values attempt to make a shadow
+    // that is legible both for dark and light themes, on top of the
+    // canvas background (rgb(150,150,150). Darker shadows would tend to
+    // blend into the foreground for a dark holo screen, and lighter shadows
+    // would be hard to spot on the canvas background. If you make adjustments,
+    // make sure to check the shadow with both dark and light themes.
+    //
+    // After making the graphics, I cut out the top right, bottom left
+    // and bottom right corners as 20x20 images, and these are reproduced by
+    // painting them in the corresponding places in the target graphics context.
+    // I then grabbed a single horizontal gradient line from the middle of the
+    // right edge,and a single vertical gradient line from the bottom. These
+    // are then painted scaled/stretched in the target to fill the gaps between
+    // the three corner images.
+    //
+    // Filenames: bl=bottom left, b=bottom, br=bottom right, r=right, tr=top right
+
+    // Normal Drop Shadow
+    private static final Image ShadowBottom = loadIcon("/icons/shadow-b.png");
+    private static final Image ShadowBottomLeft = loadIcon("/icons/shadow-bl.png");
+    private static final Image ShadowBottomRight = loadIcon("/icons/shadow-br.png");
+    private static final Image ShadowRight = loadIcon("/icons/shadow-r.png");
+    private static final Image ShadowTopRight = loadIcon("/icons/shadow-tr.png");
+    private static final Image ShadowTopLeft = loadIcon("/icons/shadow-tl.png");
+    private static final Image ShadowLeft = loadIcon("/icons/shadow-l.png");
+
+    // Small Drop Shadow
+    private static final Image Shadow2Bottom = loadIcon("/icons/shadow2-b.png");
+    private static final Image Shadow2BottomLeft = loadIcon("/icons/shadow2-bl.png");
+    private static final Image Shadow2BottomRight = loadIcon("/icons/shadow2-br.png");
+    private static final Image Shadow2Right = loadIcon("/icons/shadow2-r.png");
+    private static final Image Shadow2TopRight = loadIcon("/icons/shadow2-tr.png");
+    private static final Image Shadow2TopLeft = loadIcon("/icons/shadow2-tl.png");
+    private static final Image Shadow2Left = loadIcon("/icons/shadow2-l.png");
+}
diff --git a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
new file mode 100644
index 0000000..a6c00f7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
@@ -0,0 +1,205 @@
+/*
+ * 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 com.android.annotations.NonNull;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.Density;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
+import android.graphics.Canvas;
+import android.graphics.Outline;
+import android.graphics.Path_Delegate;
+import android.graphics.Rect;
+import android.graphics.Region.Op;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.animation.Transformation;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link ViewGroup}
+ * <p/>
+ * Through the layoutlib_create tool, the original  methods of ViewGroup have been replaced by calls
+ * to methods of the same name in this delegate class.
+ */
+public class ViewGroup_Delegate {
+
+    /**
+     * Overrides the original drawChild call in ViewGroup to draw the shadow.
+     */
+    @LayoutlibDelegate
+    /*package*/ static boolean drawChild(ViewGroup thisVG, Canvas canvas, View child,
+            long drawingTime) {
+        boolean retVal = thisVG.drawChild_Original(canvas, child, drawingTime);
+        if (child.getZ() > thisVG.getZ()) {
+            ViewOutlineProvider outlineProvider = child.getOutlineProvider();
+            Outline outline = new Outline();
+            outlineProvider.getOutline(child, outline);
+
+            if (outline.mPath != null || (outline.mRect != null && !outline.mRect.isEmpty())) {
+                int restoreTo = transformCanvas(thisVG, canvas, child);
+                drawShadow(thisVG, canvas, child, outline);
+                canvas.restoreToCount(restoreTo);
+            }
+        }
+        return retVal;
+    }
+
+    private static void drawShadow(ViewGroup parent, Canvas canvas, View child,
+            Outline outline) {
+        BufferedImage shadow = null;
+        int x = 0;
+        if (outline.mRect != null) {
+            Shadow s = getRectShadow(parent, canvas, child, outline);
+            shadow = s.mShadow;
+            x = -s.mShadowWidth;
+        } else if (outline.mPath != null) {
+            shadow = getPathShadow(child, outline, canvas);
+        }
+        if (shadow == null) {
+            return;
+        }
+        Bitmap bitmap = Bitmap_Delegate.createBitmap(shadow, false,
+                Density.getEnum(canvas.getDensity()));
+        Rect clipBounds = canvas.getClipBounds();
+        Rect newBounds = new Rect(clipBounds);
+        newBounds.left = newBounds.left + x;
+        canvas.clipRect(newBounds, Op.REPLACE);
+        canvas.drawBitmap(bitmap, x, 0, null);
+        canvas.clipRect(clipBounds, Op.REPLACE);
+    }
+
+    private static Shadow getRectShadow(ViewGroup parent, Canvas canvas, View child,
+            Outline outline) {
+        BufferedImage shadow;
+        Rect clipBounds = canvas.getClipBounds();
+        if (clipBounds.isEmpty()) {
+            return null;
+        }
+        float height = child.getZ() - parent.getZ();
+        // Draw large shadow if difference in z index is more than 10dp
+        float largeShadowThreshold = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f,
+                getMetrics(child));
+        boolean largeShadow = height > largeShadowThreshold;
+        int shadowSize = largeShadow ? ShadowPainter.SHADOW_SIZE : ShadowPainter.SMALL_SHADOW_SIZE;
+        shadow = new BufferedImage(clipBounds.width() + shadowSize, clipBounds.height(),
+                BufferedImage.TYPE_INT_ARGB);
+        Graphics2D graphics = shadow.createGraphics();
+        Rect rect = outline.mRect;
+        if (largeShadow) {
+            ShadowPainter.drawRectangleShadow(graphics,
+                    rect.left + shadowSize, rect.top, rect.width(), rect.height());
+        } else {
+            ShadowPainter.drawSmallRectangleShadow(graphics,
+                    rect.left + shadowSize, rect.top, rect.width(), rect.height());
+        }
+        graphics.dispose();
+        return new Shadow(shadow, shadowSize);
+    }
+
+    @NonNull
+    private static DisplayMetrics getMetrics(View view) {
+        Context context = view.getContext();
+        while (context instanceof ContextThemeWrapper) {
+            context = ((ContextThemeWrapper) context).getBaseContext();
+        }
+        if (context instanceof BridgeContext) {
+            return ((BridgeContext) context).getMetrics();
+        }
+        throw new RuntimeException("View " + view.getClass().getName() + " not created with the " +
+                "right context");
+    }
+
+    private static BufferedImage getPathShadow(View child, Outline outline, Canvas canvas) {
+        Rect clipBounds = canvas.getClipBounds();
+        BufferedImage image = new BufferedImage(clipBounds.width(), clipBounds.height(),
+                BufferedImage.TYPE_INT_ARGB);
+        Graphics2D graphics = image.createGraphics();
+        graphics.draw(Path_Delegate.getDelegate(outline.mPath.mNativePath).getJavaShape());
+        graphics.dispose();
+        return ShadowPainter.createDropShadow(image, ((int) child.getZ()));
+    }
+
+    // Copied from android.view.View#draw(Canvas, ViewGroup, long) and removed code paths
+    // which were never taken. Ideally, we should hook up the shadow code in the same method so
+    // that we don't have to transform the canvas twice.
+    private static int transformCanvas(ViewGroup thisVG, Canvas canvas, View child) {
+        final int restoreTo = canvas.save();
+        final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
+        int flags = thisVG.mGroupFlags;
+        Transformation transformToApply = null;
+        boolean concatMatrix = false;
+        if ((flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
+            final Transformation t = thisVG.getChildTransformation();
+            final boolean hasTransform = thisVG.getChildStaticTransformation(child, t);
+            if (hasTransform) {
+                final int transformType = t.getTransformationType();
+                transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null;
+                concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
+            }
+        }
+        concatMatrix |= childHasIdentityMatrix;
+
+        child.computeScroll();
+        int sx = child.mScrollX;
+        int sy = child.mScrollY;
+
+        canvas.translate(child.mLeft - sx, child.mTop - sy);
+        float alpha = child.getAlpha() * child.getTransitionAlpha();
+
+        if (transformToApply != null || alpha < 1 || !childHasIdentityMatrix) {
+            if (transformToApply != null || !childHasIdentityMatrix) {
+                int transX = -sx;
+                int transY = -sy;
+
+                if (transformToApply != null) {
+                    if (concatMatrix) {
+                        // Undo the scroll translation, apply the transformation matrix,
+                        // then redo the scroll translate to get the correct result.
+                        canvas.translate(-transX, -transY);
+                        canvas.concat(transformToApply.getMatrix());
+                        canvas.translate(transX, transY);
+                    }
+                    if (!childHasIdentityMatrix) {
+                        canvas.translate(-transX, -transY);
+                        canvas.concat(child.getMatrix());
+                        canvas.translate(transX, transY);
+                    }
+                }
+
+            }
+        }
+        return restoreTo;
+    }
+
+    private static class Shadow {
+        public BufferedImage mShadow;
+        public int mShadowWidth;
+
+        public Shadow(BufferedImage shadow, int shadowWidth) {
+            mShadow = shadow;
+            mShadowWidth = shadowWidth;
+        }
+
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 3d3afa4..aeb70e9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -479,6 +479,23 @@
         StyleResourceValue style = getStyleByDynamicId(resid);
 
         if (style == null) {
+            // In some cases, style may not be a dynamic id, so we do a full search.
+            ResourceReference ref = resolveId(resid);
+            if (ref != null) {
+                if (ref.isFramework()) {
+                    ref =
+                      getRenderResources().getFrameworkResource(ResourceType.STYLE, ref.getName());
+                } else {
+                    ref =
+                      getRenderResources().getProjectResource(ResourceType.STYLE, ref.getName());
+                }
+                if (ref instanceof StyleResourceValue) {
+                    style = ((StyleResourceValue) ref);
+                }
+            }
+        }
+
+        if (style == null) {
             throw new Resources.NotFoundException();
         }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
index 57fd68e..2ff8d37 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
@@ -18,6 +18,7 @@
 
 import com.android.annotations.NonNull;
 import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.SessionParams;
 import com.android.internal.R;
@@ -37,7 +38,6 @@
 import android.view.ViewGroup.LayoutParams;
 import android.widget.ActionMenuPresenter;
 import android.widget.FrameLayout;
-import android.widget.LinearLayout;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.RelativeLayout;
@@ -49,15 +49,23 @@
     private static final String LAYOUT_ATTR_NAME = "windowActionBarFullscreenDecorLayout";
 
     // The Action Bar
-    @NonNull private CustomActionBarWrapper mActionBar;
+    @NonNull
+    private CustomActionBarWrapper mActionBar;
 
     // Store another reference to the context so that we don't have to cast it repeatedly.
-    @NonNull private final BridgeContext mBridgeContext;
+    @NonNull
+    private final BridgeContext mBridgeContext;
 
-    @NonNull private FrameLayout mContentRoot;
+    @NonNull
+    private FrameLayout mContentRoot;
 
     // A fake parent for measuring views.
-    @Nullable private ViewGroup mMeasureParent;
+    @Nullable
+    private ViewGroup mMeasureParent;
+
+    // A Layout that contains the inflated action bar. The menu popup is added to this layout.
+    @NonNull
+    private final RelativeLayout mEnclosingLayout;
 
     /**
      * Inflate the action bar and attach it to {@code parentView}
@@ -90,20 +98,25 @@
         if (layoutId == 0) {
             throw new RuntimeException(error);
         }
+        // Create a RelativeLayout to hold the action bar. The layout is needed so that we may
+        // add the menu popup to it.
+        mEnclosingLayout = new RelativeLayout(mBridgeContext);
+        setMatchParent(mEnclosingLayout);
+        parentView.addView(mEnclosingLayout);
+
         // Inflate action bar layout.
-        View decorContent = LayoutInflater.from(context).inflate(layoutId, parentView, true);
+        View decorContent = LayoutInflater.from(context).inflate(layoutId, mEnclosingLayout, true);
 
         mActionBar = CustomActionBarWrapper.getActionBarWrapper(context, params, decorContent);
 
-        FrameLayout contentRoot = (FrameLayout) parentView.findViewById(android.R.id.content);
+        FrameLayout contentRoot = (FrameLayout) mEnclosingLayout.findViewById(android.R.id.content);
 
         // If something went wrong and we were not able to initialize the content root,
         // just add a frame layout inside this and return.
         if (contentRoot == null) {
             contentRoot = new FrameLayout(context);
-            contentRoot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
-                    LayoutParams.MATCH_PARENT));
-            parentView.addView(contentRoot);
+            setMatchParent(contentRoot);
+            mEnclosingLayout.addView(contentRoot);
             mContentRoot = contentRoot;
         } else {
             mContentRoot = contentRoot;
@@ -112,70 +125,49 @@
         }
     }
 
+    private void setMatchParent(View view) {
+        view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT));
+    }
+
     /**
      * Creates a Popup and adds it to the content frame. It also adds another {@link FrameLayout} to
      * the content frame which shall serve as the new content root.
      */
     public void createMenuPopup() {
-        assert mContentRoot.getId() == android.R.id.content
+        assert mEnclosingLayout.getChildCount() == 1
                 : "Action Bar Menus have already been created.";
 
         if (!isOverflowPopupNeeded()) {
             return;
         }
 
-        // Create a layout to hold the menus and the user's content.
-        RelativeLayout layout = new RelativeLayout(mActionBar.getPopupContext());
-        layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT));
-        mContentRoot.addView(layout);
-        // Create a layout for the user's content.
-        FrameLayout contentRoot = new FrameLayout(mBridgeContext);
-        contentRoot.setLayoutParams(new LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-        // Add contentRoot and menus to the layout.
-        layout.addView(contentRoot);
-        layout.addView(createMenuView());
-        // ContentRoot is now the view we just created.
-        mContentRoot = contentRoot;
-    }
-
-    /**
-     * Returns a {@link LinearLayout} containing the menu list view to be embedded in a
-     * {@link RelativeLayout}
-     */
-    @NonNull
-    private View createMenuView() {
         DisplayMetrics metrics = mBridgeContext.getMetrics();
         MenuBuilder menu = mActionBar.getMenuBuilder();
         OverflowMenuAdapter adapter = new OverflowMenuAdapter(menu, mActionBar.getPopupContext());
 
-        LinearLayout layout = new LinearLayout(mActionBar.getPopupContext());
+        ListView listView = new ListView(mActionBar.getPopupContext(), null,
+                R.attr.dropDownListViewStyle);
         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
                 measureContentWidth(adapter), LayoutParams.WRAP_CONTENT);
         layoutParams.addRule(RelativeLayout.ALIGN_PARENT_END);
         if (mActionBar.isSplit()) {
             layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
-            // TODO: Find correct value instead of hardcoded 10dp.
-            layoutParams.bottomMargin = getPixelValue("-10dp", metrics);
+            layoutParams.bottomMargin = getActionBarHeight() + mActionBar.getMenuPopupMargin();
         } else {
-            layoutParams.topMargin = getPixelValue("-10dp", metrics);
+            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+            layoutParams.topMargin = getActionBarHeight() + mActionBar.getMenuPopupMargin();
         }
-        layout.setLayoutParams(layoutParams);
+        layoutParams.setMarginEnd(getPixelValue("5dp", metrics));
+        listView.setLayoutParams(layoutParams);
+        listView.setAdapter(adapter);
         final TypedArray a = mActionBar.getPopupContext().obtainStyledAttributes(null,
                 R.styleable.PopupWindow, R.attr.popupMenuStyle, 0);
-        layout.setBackground(a.getDrawable(R.styleable.PopupWindow_popupBackground));
-        layout.setDividerDrawable(a.getDrawable(R.attr.actionBarDivider));
+        listView.setBackground(a.getDrawable(R.styleable.PopupWindow_popupBackground));
+        listView.setDivider(a.getDrawable(R.attr.actionBarDivider));
         a.recycle();
-        layout.setOrientation(LinearLayout.VERTICAL);
-        layout.setDividerPadding(getPixelValue("12dp", metrics));
-        layout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
-
-        ListView listView = new ListView(mActionBar.getPopupContext(), null,
-                R.attr.dropDownListViewStyle);
-        listView.setAdapter(adapter);
-        layout.addView(listView);
-        return layout;
+        listView.setElevation(mActionBar.getMenuPopupElevation());
+        mEnclosingLayout.addView(listView);
     }
 
     private boolean isOverflowPopupNeeded() {
@@ -244,9 +236,30 @@
         return maxWidth;
     }
 
-    private int getPixelValue(@NonNull String value, @NonNull DisplayMetrics metrics) {
+    static int getPixelValue(@NonNull String value, @NonNull DisplayMetrics metrics) {
         TypedValue typedValue = ResourceHelper.getValue(null, value, false /*requireUnit*/);
         return (int) typedValue.getDimension(metrics);
     }
 
+    // TODO: This is duplicated from RenderSessionImpl.
+    private int getActionBarHeight() {
+        RenderResources resources = mBridgeContext.getRenderResources();
+        DisplayMetrics metrics = mBridgeContext.getMetrics();
+        ResourceValue value = resources.findItemInTheme("actionBarSize", true);
+
+        // resolve it
+        value = resources.resolveResValue(value);
+
+        if (value != null) {
+            // get the numerical value, if available
+            TypedValue typedValue = ResourceHelper.getValue("actionBarSize", value.getValue(),
+                    true);
+            if (typedValue != null) {
+                // compute the pixel value based on the display metrics
+                return (int) typedValue.getDimension(metrics);
+
+            }
+        }
+        return 0;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
index 70b9cc3..6db722e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
@@ -65,18 +65,17 @@
      * Returns a wrapper around different implementations of the Action Bar to provide a common API.
      *
      * @param decorContent the top level view returned by inflating
-                     * ?attr/windowActionBarFullscreenDecorLayout
+     *                     ?attr/windowActionBarFullscreenDecorLayout
      */
     @NonNull
     public static CustomActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context,
             @NonNull SessionParams params, @NonNull View decorContent) {
         View view = decorContent.findViewById(R.id.action_bar);
         if (view instanceof Toolbar) {
-            return new ToolbarWrapper(context, params, ((Toolbar) view)
-            );
+            return new ToolbarWrapper(context, params, ((Toolbar) view));
         } else if (view instanceof ActionBarView) {
-            return new WindowActionBarWrapper(context, params, decorContent, ((ActionBarView) view)
-            );
+            return new WindowActionBarWrapper(context, params, decorContent,
+                    ((ActionBarView) view));
         } else {
             throw new IllegalStateException("Can't make an action bar out of " +
                     view.getClass().getSimpleName());
@@ -174,6 +173,13 @@
     @NonNull
     abstract DecorToolbar getDecorToolbar();
 
+    abstract int getMenuPopupElevation();
+
+    /**
+     * Margin between the menu popup and the action bar.
+     */
+    abstract int getMenuPopupMargin();
+
     // ---- The implementations ----
 
     /**
@@ -226,25 +232,38 @@
         DecorToolbar getDecorToolbar() {
             return mToolbar.getWrapper();
         }
+
+        @Override
+        int getMenuPopupElevation() {
+            return 10;
+        }
+
+        @Override
+        int getMenuPopupMargin() {
+            return 0;
+        }
     }
 
     /**
      * Holo theme uses {@link WindowDecorActionBar} as the action bar. This wrapper provides
      * access to it using a common API.
      */
-    private static class WindowActionBarWrapper extends CustomActionBarWrapper{
+    private static class WindowActionBarWrapper extends CustomActionBarWrapper {
 
         @NonNull
         private final WindowDecorActionBar mActionBar;
+        @NonNull
         private final ActionBarView mActionBarView;
+        @NonNull
+        private final View mDecorContentRoot;
         private MenuBuilder mMenuBuilder;
 
         public WindowActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
                 @NonNull View decorContentRoot, @NonNull ActionBarView actionBarView) {
-            super(context, params, new WindowDecorActionBar(decorContentRoot)
-            );
+            super(context, params, new WindowDecorActionBar(decorContentRoot));
             mActionBarView = actionBarView;
             mActionBar = ((WindowDecorActionBar) super.mActionBar);
+            mDecorContentRoot = decorContentRoot;
         }
 
         @Override
@@ -270,7 +289,7 @@
             }
 
             // Set action bar to be split, if needed.
-            ViewGroup splitView = (ViewGroup) mActionBarView.findViewById(R.id.split_action_bar);
+            ViewGroup splitView = (ViewGroup) mDecorContentRoot.findViewById(R.id.split_action_bar);
             if (splitView != null) {
                 mActionBarView.setSplitView(splitView);
                 Resources res = mContext.getResources();
@@ -314,6 +333,16 @@
             return mActionBarView;
         }
 
+        @Override
+        int getMenuPopupElevation() {
+            return 0;
+        }
+
+        @Override
+        int getMenuPopupMargin() {
+            return -ActionBarLayout.getPixelValue("10dp", mContext.getMetrics());
+        }
+
         // TODO: Use an adapter, like List View to set up tabs.
         @SuppressWarnings("deprecation")  // For Tab
         private void setupTabs(int num) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index b677131..669e6b5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -57,63 +57,59 @@
 
     public Result render() {
         checkLock();
-        try {
-            // get the drawable resource value
-            DrawableParams params = getParams();
-            HardwareConfig hardwareConfig = params.getHardwareConfig();
-            ResourceValue drawableResource = params.getDrawable();
+        // get the drawable resource value
+        DrawableParams params = getParams();
+        HardwareConfig hardwareConfig = params.getHardwareConfig();
+        ResourceValue drawableResource = params.getDrawable();
 
-            // resolve it
-            BridgeContext context = getContext();
-            drawableResource = context.getRenderResources().resolveResValue(drawableResource);
+        // resolve it
+        BridgeContext context = getContext();
+        drawableResource = context.getRenderResources().resolveResValue(drawableResource);
 
-            if (drawableResource == null ||
-                    drawableResource.getResourceType() != ResourceType.DRAWABLE) {
-                return Status.ERROR_NOT_A_DRAWABLE.createResult();
-            }
-
-            // create a simple FrameLayout
-            FrameLayout content = new FrameLayout(context);
-
-            // get the actual Drawable object to draw
-            Drawable d = ResourceHelper.getDrawable(drawableResource, context);
-            content.setBackground(d);
-
-            // set the AttachInfo on the root view.
-            AttachInfo_Accessor.setAttachInfo(content);
-
-
-            // measure
-            int w = hardwareConfig.getScreenWidth();
-            int h = hardwareConfig.getScreenHeight();
-            int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
-            int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
-            content.measure(w_spec, h_spec);
-
-            // now do the layout.
-            content.layout(0, 0, w, h);
-
-            // preDraw setup
-            AttachInfo_Accessor.dispatchOnPreDraw(content);
-
-            // draw into a new image
-            BufferedImage image = getImage(w, h);
-
-            // create an Android bitmap around the BufferedImage
-            Bitmap bitmap = Bitmap_Delegate.createBitmap(image,
-                    true /*isMutable*/, hardwareConfig.getDensity());
-
-            // create a Canvas around the Android bitmap
-            Canvas canvas = new Canvas(bitmap);
-            canvas.setDensity(hardwareConfig.getDensity().getDpiValue());
-
-            // and draw
-            content.draw(canvas);
-
-            return Status.SUCCESS.createResult(image);
-        } catch (IOException e) {
-            return ERROR_UNKNOWN.createResult(e.getMessage(), e);
+        if (drawableResource == null ||
+                drawableResource.getResourceType() != ResourceType.DRAWABLE) {
+            return Status.ERROR_NOT_A_DRAWABLE.createResult();
         }
+
+        // create a simple FrameLayout
+        FrameLayout content = new FrameLayout(context);
+
+        // get the actual Drawable object to draw
+        Drawable d = ResourceHelper.getDrawable(drawableResource, context);
+        content.setBackground(d);
+
+        // set the AttachInfo on the root view.
+        AttachInfo_Accessor.setAttachInfo(content);
+
+
+        // measure
+        int w = hardwareConfig.getScreenWidth();
+        int h = hardwareConfig.getScreenHeight();
+        int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
+        int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
+        content.measure(w_spec, h_spec);
+
+        // now do the layout.
+        content.layout(0, 0, w, h);
+
+        // preDraw setup
+        AttachInfo_Accessor.dispatchOnPreDraw(content);
+
+        // draw into a new image
+        BufferedImage image = getImage(w, h);
+
+        // create an Android bitmap around the BufferedImage
+        Bitmap bitmap = Bitmap_Delegate.createBitmap(image,
+                true /*isMutable*/, hardwareConfig.getDensity());
+
+        // create a Canvas around the Android bitmap
+        Canvas canvas = new Canvas(bitmap);
+        canvas.setDensity(hardwareConfig.getDensity().getDpiValue());
+
+        // and draw
+        content.draw(canvas);
+
+        return Status.SUCCESS.createResult(image);
     }
 
     protected BufferedImage getImage(int w, int h) {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 2fcdf34..4e6f456 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -162,6 +162,11 @@
         "android.view.WindowManagerGlobal#getWindowManagerService",
         "android.view.inputmethod.InputMethodManager#getInstance",
         "android.view.MenuInflater#registerMenu",
+        "android.view.RenderNode#nCreate",
+        "android.view.RenderNode#nDestroyRenderNode",
+        "android.view.RenderNode#nSetElevation",
+        "android.view.RenderNode#nGetElevation",
+        "android.view.ViewGroup#drawChild",
         "com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
         "com.android.internal.util.XmlUtils#convertValueToInt",
         "com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
index 3d89c68..ae4a57d 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
@@ -112,6 +112,7 @@
         //   The implementation of this 'delegate' method is done in layoutlib_bridge.
 
         int accessDelegate = access;
+        access = access & ~Opcodes.ACC_PRIVATE;  // If private, make it package protected.
 
         MethodVisitor mwOriginal = super.visitMethod(access, name + ORIGINAL_SUFFIX,
                                                      desc, signature, exceptions);
diff --git a/tools/split-select/RuleGenerator.cpp b/tools/split-select/RuleGenerator.cpp
index 72bb0c7..83c9795 100644
--- a/tools/split-select/RuleGenerator.cpp
+++ b/tools/split-select/RuleGenerator.cpp
@@ -38,7 +38,7 @@
         densityRule->op = Rule::AND_SUBRULES;
 
         const bool hasAnyDensity = std::find(allDensities.begin(),
-                allDensities.end(), ResTable_config::DENSITY_ANY) != allDensities.end();
+                allDensities.end(), (int) ResTable_config::DENSITY_ANY) != allDensities.end();
 
         if (hasAnyDensity) {
             sp<Rule> version = new Rule();
diff --git a/tools/split-select/RuleGenerator_test.cpp b/tools/split-select/RuleGenerator_test.cpp
index 778d604..470cadc 100644
--- a/tools/split-select/RuleGenerator_test.cpp
+++ b/tools/split-select/RuleGenerator_test.cpp
@@ -47,10 +47,10 @@
 }
 
 TEST(RuleGeneratorTest, densityConstantsAreSane) {
-    EXPECT_LT(263, ConfigDescription::DENSITY_XHIGH);
-    EXPECT_GT(262, ConfigDescription::DENSITY_HIGH);
-    EXPECT_LT(363, ConfigDescription::DENSITY_XXHIGH);
-    EXPECT_GT(362, ConfigDescription::DENSITY_XHIGH);
+    EXPECT_LT(263, (int) ConfigDescription::DENSITY_XHIGH);
+    EXPECT_GT(262, (int) ConfigDescription::DENSITY_HIGH);
+    EXPECT_LT(363, (int) ConfigDescription::DENSITY_XXHIGH);
+    EXPECT_GT(362, (int) ConfigDescription::DENSITY_XHIGH);
 }
 
 TEST(RuleGeneratorTest, testDensityRules) {
diff --git a/tools/split-select/TestRules.cpp b/tools/split-select/TestRules.cpp
index f980dc4..86ccd6a 100644
--- a/tools/split-select/TestRules.cpp
+++ b/tools/split-select/TestRules.cpp
@@ -75,7 +75,7 @@
         const char*, const char*,
         const sp<Rule>& actual, const Rule& expected) {
     const String8 expectedStr(expected.toJson());
-    const String8 actualStr(actual != NULL ? actual->toJson() : "");
+    const String8 actualStr(actual != NULL ? actual->toJson() : String8());
 
     if (expectedStr != actualStr) {
         return ::testing::AssertionFailure()