Merge "Adds an enabled state in UserInfo instead of DevicePolicyManager"
diff --git a/api/current.txt b/api/current.txt
index 54c9d90..7615d4f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4985,8 +4985,10 @@
   public class DevicePolicyManager {
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+    method public void clearForwardingIntentFilters(android.content.ComponentName);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+    method public void forwardMatchingIntents(android.content.ComponentName, android.content.IntentFilter, int);
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
     method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5046,6 +5048,8 @@
     field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
     field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "defaultManagedProfileName";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "deviceAdminPackageName";
+    field public static int FLAG_TO_MANAGED_PROFILE;
+    field public static int FLAG_TO_PRIMARY_USER;
     field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
     field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
     field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
@@ -7762,6 +7766,8 @@
   public class LauncherApps {
     method public synchronized void addOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener);
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
+    method public boolean isActivityEnabledForProfile(android.content.ComponentName, android.os.UserHandle);
+    method public boolean isPackageEnabledForProfile(java.lang.String, android.os.UserHandle);
     method public synchronized void removeOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public void startActivityForProfile(android.content.ComponentName, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 391c197..74ccbc2 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -145,7 +145,7 @@
     static const char kInstructionSet[] = "x86_64";
 #elif defined(__arm__)
     static const char kInstructionSet[] = "arm";
-#elif defined(__x86__)
+#elif defined(__i386__)
     static const char kInstructionSet[] = "x86";
 #elif defined (__mips__)
     static const char kInstructionSet[] = "mips";
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 1780e03..3dc024e 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -156,12 +156,12 @@
     return NO_ERROR;
 }
 
-status_t BootAnimation::initTexture(void* buffer, size_t len)
+status_t BootAnimation::initTexture(const Animation::Frame& frame)
 {
     //StopWatch watch("blah");
 
     SkBitmap bitmap;
-    SkMemoryStream  stream(buffer, len);
+    SkMemoryStream  stream(frame.map->getDataPtr(), frame.map->getDataLength());
     SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
     if (codec) {
         codec->setDitherImage(false);
@@ -171,6 +171,11 @@
         delete codec;
     }
 
+    // FileMap memory is never released until application exit.
+    // Release it now as the texture is already loaded and the memory used for
+    // the packed resource can be released.
+    frame.map->release();
+
     // ensure we can call getPixels(). No need to call unlock, since the
     // bitmap will go out of scope when we return from this method.
     bitmap.lockPixels();
@@ -409,6 +414,7 @@
 
     String8 desString((char const*)descMap->getDataPtr(),
             descMap->getDataLength());
+    descMap->release();
     char const* s = desString.string();
 
     Animation animation;
@@ -533,9 +539,7 @@
                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                     }
-                    initTexture(
-                            frame.map->getDataPtr(),
-                            frame.map->getDataLength());
+                    initTexture(frame);
                 }
 
                 if (!clearReg.isEmpty()) {
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 22963c2..ba1c507 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -79,7 +79,7 @@
     };
 
     status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
-    status_t initTexture(void* buffer, size_t len);
+    status_t initTexture(const Animation::Frame& frame);
     bool android();
     bool movie();
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 018e949..9239faf 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1627,13 +1627,6 @@
         public int lastTrimLevel;
 
         /**
-         * Constant for {@link #importance}: this is a persistent process.
-         * Only used when reporting to process observers.
-         * @hide
-         */
-        public static final int IMPORTANCE_PERSISTENT = 50;
-
-        /**
          * Constant for {@link #importance}: this process is running the
          * foreground UI.
          */
@@ -1748,9 +1741,16 @@
          */
         public int importanceReasonImportance;
 
+        /**
+         * Current process state, as per PROCESS_STATE_* constants.
+         * @hide
+         */
+        public int processState;
+
         public RunningAppProcessInfo() {
             importance = IMPORTANCE_FOREGROUND;
             importanceReasonCode = REASON_UNKNOWN;
+            processState = PROCESS_STATE_IMPORTANT_FOREGROUND;
         }
         
         public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) {
@@ -1776,6 +1776,7 @@
             dest.writeInt(importanceReasonPid);
             ComponentName.writeToParcel(importanceReasonComponent, dest);
             dest.writeInt(importanceReasonImportance);
+            dest.writeInt(processState);
         }
 
         public void readFromParcel(Parcel source) {
@@ -1791,6 +1792,7 @@
             importanceReasonPid = source.readInt();
             importanceReasonComponent = ComponentName.readFromParcel(source);
             importanceReasonImportance = source.readInt();
+            processState = source.readInt();
         }
 
         public static final Creator<RunningAppProcessInfo> CREATOR = 
diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl
index e587912..ecf2c73 100644
--- a/core/java/android/app/IProcessObserver.aidl
+++ b/core/java/android/app/IProcessObserver.aidl
@@ -20,7 +20,7 @@
 oneway interface IProcessObserver {
 
     void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
-    void onImportanceChanged(int pid, int uid, int importance);
+    void onProcessStateChanged(int pid, int uid, int procState);
     void onProcessDied(int pid, int uid);
 
 }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 5f8ebbe..58d707c 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -651,6 +651,10 @@
      *         not "image/*"
      */
     public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+        if (imageUri == null) {
+            throw new IllegalArgumentException("Image URI must not be null");
+        }
+
         if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())) {
             throw new IllegalArgumentException("Image URI must be of the "
                     + ContentResolver.SCHEME_CONTENT + " scheme type");
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e437edb..6f68dfb 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -172,6 +172,16 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SET_NEW_PASSWORD
             = "android.app.action.SET_NEW_PASSWORD";
+    /**
+     * Flag for {@link #forwardMatchingIntents}: the intents will forwarded to the primary user.
+     */
+    public static int FLAG_TO_PRIMARY_USER = 0x0001;
+
+    /**
+     * Flag for {@link #forwardMatchingIntents}: the intents will be forwarded to the managed
+     * profile.
+     */
+    public static int FLAG_TO_MANAGED_PROFILE = 0x0002;
 
     /**
      * Return true if the given administrator component is currently
@@ -1932,6 +1942,39 @@
     }
 
     /**
+     * Called by a profile owner to forward intents sent from the managed profile to the owner, or
+     * from the owner to the managed profile.
+     * If an intent matches this intent filter, then activities belonging to the other user can
+     * respond to this intent.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param filter if an intent matches this IntentFilter, then it can be forwarded.
+     */
+    public void forwardMatchingIntents(ComponentName admin, IntentFilter filter, int flags) {
+        if (mService != null) {
+            try {
+                mService.forwardMatchingIntents(admin, filter, flags);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * Called by a profile owner to remove all the forwarding intent filters from the current user
+     * and from the owner.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     */
+    public void clearForwardingIntentFilters(ComponentName admin) {
+        if (mService != null) {
+            try {
+                mService.clearForwardingIntentFilters(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
      * Called by a profile or device owner to get the application restrictions for a given target
      * application running in the managed profile.
      *
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 51ea7b1..495a5f9 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -120,4 +120,6 @@
     Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
 
     void setUserRestriction(in ComponentName who, in String key, boolean enable);
+    void forwardMatchingIntents(in ComponentName admin, in IntentFilter filter, int flags);
+    void clearForwardingIntentFilters(in ComponentName admin);
 }
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 796b113..0acf043 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -35,4 +35,6 @@
     ResolveInfo resolveActivity(in Intent intent, in UserHandle user);
     void startActivityAsUser(in ComponentName component, in Rect sourceBounds,
             in Bundle opts, in UserHandle user);
+    boolean isPackageEnabled(String packageName, in UserHandle user);
+    boolean isActivityEnabled(in ComponentName component, in UserHandle user);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 488e25f..cf9a296 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -111,6 +111,8 @@
 
     ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
 
+    boolean canForwardTo(in Intent intent, String resolvedType, int userIdFrom, int userIdDest);
+
     List<ResolveInfo> queryIntentActivities(in Intent intent, 
             String resolvedType, int flags, int userId);
 
@@ -245,6 +247,10 @@
 
     void clearPackagePersistentPreferredActivities(String packageName, int userId);
 
+    void addForwardingIntentFilter(in IntentFilter filter, int userIdOrig, int userIdDest);
+
+    void clearForwardingIntentFilters(int userIdOrig);
+
     /**
      * Report the set of 'Home' activity candidates, plus (if any) which of them
      * is the current "always use this one" setting.
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 5187181..8025b60 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -187,6 +187,39 @@
     }
 
     /**
+     * Checks if the package is installed and enabled for a profile.
+     *
+     * @param packageName The package to check.
+     * @param user The UserHandle of the profile.
+     *
+     * @return true if the package exists and is enabled.
+     */
+    public boolean isPackageEnabledForProfile(String packageName, UserHandle user) {
+        try {
+            return mService.isPackageEnabled(packageName, user);
+        } catch (RemoteException re) {
+            return false;
+        }
+    }
+
+    /**
+     * Checks if the activity exists and it enabled for a profile.
+     *
+     * @param component The activity to check.
+     * @param user The UserHandle of the profile.
+     *
+     * @return true if the activity exists and is enabled.
+     */
+    public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) {
+        try {
+            return mService.isActivityEnabled(component, user);
+        } catch (RemoteException re) {
+            return false;
+        }
+    }
+
+
+    /**
      * Adds a listener for changes to packages in current and managed profiles.
      *
      * @param listener The listener to add.
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index f8160c8..bc2d7ec 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -259,7 +259,7 @@
     public InputMethodInfo(String packageName, String className,
             CharSequence label, String settingsActivity) {
         this(buildDummyResolveInfo(packageName, className, label), false, settingsActivity, null,
-                0, false);
+                0, false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */);
     }
 
     /**
@@ -269,6 +269,17 @@
     public InputMethodInfo(ResolveInfo ri, boolean isAuxIme,
             String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
             boolean forceDefault) {
+        this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId,
+                forceDefault, true /* supportsSwitchingToNextInputMethod */);
+    }
+
+    /**
+     * Temporary API for creating a built-in input method for test.
+     * @hide
+     */
+    public InputMethodInfo(ResolveInfo ri, boolean isAuxIme,
+            String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
+            boolean forceDefault, boolean supportsSwitchingToNextInputMethod) {
         final ServiceInfo si = ri.serviceInfo;
         mService = ri;
         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -277,7 +288,7 @@
         mIsAuxIme = isAuxIme;
         mSubtypes = new InputMethodSubtypeArray(subtypes);
         mForceDefault = forceDefault;
-        mSupportsSwitchingToNextInputMethod = true;
+        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
     }
 
     private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index c914e52..efb246a 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -701,7 +701,7 @@
      */
     @Deprecated
     public static void enablePlatformNotifications() {
-        getFactory().getStatics().setPlatformNotificationsEnabled(true);
+        // noop
     }
 
     /**
@@ -713,7 +713,7 @@
      */
     @Deprecated
     public static void disablePlatformNotifications() {
-        getFactory().getStatics().setPlatformNotificationsEnabled(false);
+        // noop
     }
 
     /**
@@ -1610,6 +1610,8 @@
      * @return the address, or if no address is found, null
      */
     public static String findAddress(String addr) {
+        // TODO: Rewrite this in Java so it is not needed to start up chromium
+        // Could also be deprecated
         return getFactory().getStatics().findAddress(addr);
     }
 
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
new file mode 100644
index 0000000..2f74372
--- /dev/null
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -0,0 +1,112 @@
+/*
+ * 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.app;
+
+import android.app.Activity;
+import android.app.AppGlobals;
+import android.os.Bundle;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.app.ActivityManagerNative;
+import android.os.RemoteException;
+import android.util.Slog;
+import java.util.List;
+import java.util.Set;
+
+
+
+
+/*
+ * This is used in conjunction with DevicePolicyManager.setForwardingIntents to enable intents to be
+ * passed in and out of a managed profile.
+ */
+
+public class IntentForwarderActivity extends Activity  {
+
+    public static String TAG = "IntentForwarderActivity";
+
+    public static String FORWARD_INTENT_TO_USER_OWNER
+            = "com.android.internal.app.ForwardIntentToUserOwner";
+
+    public static String FORWARD_INTENT_TO_MANAGED_PROFILE
+            = "com.android.internal.app.ForwardIntentToManagedProfile";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intentReceived = getIntent();
+
+        String className = intentReceived.getComponent().getClassName();
+        final UserHandle userDest;
+
+        if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) {
+            userDest = UserHandle.OWNER;
+        } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+            userDest = getManagedProfile();
+        } else {
+            Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
+            userDest = null;
+        }
+        if (userDest == null) { // This covers the case where there is no managed profile.
+            finish();
+            return;
+        }
+        Intent newIntent = new Intent(intentReceived);
+        newIntent.setComponent(null);
+        newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+                |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+        int callingUserId = getUserId();
+        IPackageManager ipm = AppGlobals.getPackageManager();
+        String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver());
+        boolean canForward = false;
+        try {
+            canForward = ipm.canForwardTo(newIntent, resolvedType, callingUserId,
+                    userDest.getIdentifier());
+        } catch (RemoteException e) {
+            Slog.e(TAG, "PackageManagerService is dead?");
+        }
+        if (canForward) {
+            startActivityAsUser(newIntent, userDest);
+        } else {
+            Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
+                    + callingUserId + " to user " + userDest.getIdentifier());
+        }
+        finish();
+    }
+
+    /**
+     * Returns the managed profile for this device or null if there is no managed
+     * profile.
+     *
+     * TODO: Remove the assumption that there is only one managed profile
+     * on the device.
+     */
+    private UserHandle getManagedProfile() {
+        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
+        List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER);
+        for (UserInfo userInfo : relatedUsers) {
+            if (userInfo.isManagedProfile()) return new UserHandle(userInfo.id);
+        }
+        Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
+                + " has been called, but there is no managed profile");
+        return null;
+    }
+}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
index dcc0a4c..cba09d1 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.inputmethod;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
 
 import android.content.Context;
@@ -119,14 +120,14 @@
         }
     }
 
-    private static class InputMethodAndSubtypeCircularList {
+    private static class InputMethodAndSubtypeList {
         private final Context mContext;
         // Used to load label
         private final PackageManager mPm;
         private final String mSystemLocaleStr;
         private final InputMethodSettings mSettings;
 
-        public InputMethodAndSubtypeCircularList(Context context, InputMethodSettings settings) {
+        public InputMethodAndSubtypeList(Context context, InputMethodSettings settings) {
             mContext = context;
             mSettings = settings;
             mPm = context.getPackageManager();
@@ -152,38 +153,6 @@
                             }
                         });
 
-        public ImeSubtypeListItem getNextInputMethod(
-                boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
-            if (imi == null) {
-                return null;
-            }
-            final List<ImeSubtypeListItem> imList =
-                    getSortedInputMethodAndSubtypeList();
-            if (imList.size() <= 1) {
-                return null;
-            }
-            final int N = imList.size();
-            final int currentSubtypeId =
-                    subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
-                            subtype.hashCode()) : NOT_A_SUBTYPE_ID;
-            for (int i = 0; i < N; ++i) {
-                final ImeSubtypeListItem isli = imList.get(i);
-                if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
-                    if (!onlyCurrentIme) {
-                        return imList.get((i + 1) % N);
-                    }
-                    for (int j = 0; j < N - 1; ++j) {
-                        final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
-                        if (candidate.mImi.equals(imi)) {
-                            return candidate;
-                        }
-                    }
-                    return null;
-                }
-            }
-            return null;
-        }
-
         public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
             return getSortedInputMethodAndSubtypeList(true, false, false);
         }
@@ -247,7 +216,38 @@
     private final ArrayDeque<SubtypeParams> mTypedSubtypeHistory = new ArrayDeque<SubtypeParams>();
     private final Object mLock = new Object();
     private final InputMethodSettings mSettings;
-    private InputMethodAndSubtypeCircularList mSubtypeList;
+    private InputMethodAndSubtypeList mSubtypeList;
+
+    @VisibleForTesting
+    public static ImeSubtypeListItem getNextInputMethodImpl(List<ImeSubtypeListItem> imList,
+            boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
+        if (imi == null) {
+            return null;
+        }
+        if (imList.size() <= 1) {
+            return null;
+        }
+        final int N = imList.size();
+        final int currentSubtypeId =
+                subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
+                        subtype.hashCode()) : NOT_A_SUBTYPE_ID;
+        for (int i = 0; i < N; ++i) {
+            final ImeSubtypeListItem isli = imList.get(i);
+            if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
+                if (!onlyCurrentIme) {
+                    return imList.get((i + 1) % N);
+                }
+                for (int j = 0; j < N - 1; ++j) {
+                    final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
+                    if (candidate.mImi.equals(imi)) {
+                        return candidate;
+                    }
+                }
+                return null;
+            }
+        }
+        return null;
+    }
 
     public InputMethodSubtypeSwitchingController(InputMethodSettings settings) {
         mSettings = settings;
@@ -278,14 +278,15 @@
 
     public void resetCircularListLocked(Context context) {
         synchronized(mLock) {
-            mSubtypeList = new InputMethodAndSubtypeCircularList(context, mSettings);
+            mSubtypeList = new InputMethodAndSubtypeList(context, mSettings);
         }
     }
 
     public ImeSubtypeListItem getNextInputMethod(
             boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
         synchronized(mLock) {
-            return mSubtypeList.getNextInputMethod(onlyCurrentIme, imi, subtype);
+            return getNextInputMethodImpl(mSubtypeList.getSortedInputMethodAndSubtypeList(),
+                    onlyCurrentIme, imi, subtype);
         }
     }
 
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 799782d..6591d60 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -226,16 +226,17 @@
     jint* imgOffsets = env->GetIntArrayElements(offsets, NULL);
     jint* imgStrides = env->GetIntArrayElements(strides, NULL);
     YuvToJpegEncoder* encoder = YuvToJpegEncoder::create(format, imgStrides);
-    if (encoder == NULL) {
-        return JNI_FALSE;
+    jboolean result = JNI_FALSE;
+    if (encoder != NULL) {
+        encoder->encode(strm, yuv, width, height, imgOffsets, jpegQuality);
+        delete encoder;
+        result = JNI_TRUE;
     }
-    encoder->encode(strm, yuv, width, height, imgOffsets, jpegQuality);
 
-    delete encoder;
     env->ReleaseByteArrayElements(inYuv, yuv, 0);
     env->ReleaseIntArrayElements(offsets, imgOffsets, 0);
     env->ReleaseIntArrayElements(strides, imgStrides, 0);
-    return JNI_TRUE;
+    return result;
 }
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 35cdf60..b92c992 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -37,6 +37,8 @@
     jmethodID callOnFinished;
 } gRenderNodeAnimatorClassInfo;
 
+#ifdef USE_OPENGL_RENDERER
+
 static JNIEnv* getEnv(JavaVM* vm) {
     JNIEnv* env;
     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
@@ -93,6 +95,8 @@
     obj->decStrong(0);
 }
 
+#endif
+
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -100,9 +104,11 @@
 const char* const kClassPathName = "android/view/RenderNodeAnimator";
 
 static JNINativeMethod gMethods[] = {
+#ifdef USE_OPENGL_RENDERER
     { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IIF)J", (void*) createAnimator },
     { "nSetDuration", "(JI)V", (void*) setDuration },
     { "nUnref", "(J)V", (void*) unref },
+#endif
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/core/jni/android_view_RenderNodeAnimator.h b/core/jni/android_view_RenderNodeAnimator.h
index d84003f..760ca91 100644
--- a/core/jni/android_view_RenderNodeAnimator.h
+++ b/core/jni/android_view_RenderNodeAnimator.h
@@ -16,6 +16,8 @@
 
 #include "jni.h"
 
+#ifdef USE_OPENGL_RENDERER
+
 #include <Animator.h>
 
 namespace android {
@@ -34,3 +36,5 @@
 };
 
 }
+
+#endif
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index a61fa87..c58bf04 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -92,14 +92,10 @@
     if (WIFEXITED(status)) {
       if (WEXITSTATUS(status)) {
         ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
-      } else if (false) {
-        ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
       }
     } else if (WIFSIGNALED(status)) {
       if (WTERMSIG(status) != SIGKILL) {
-        ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
-      } else if (false) {
-        ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
+        ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status));
       }
 #ifdef WCOREDUMP
       if (WCOREDUMP(status)) {
@@ -117,8 +113,10 @@
     }
   }
 
-  if (pid < 0) {
-    ALOGW("Zygote SIGCHLD error in waitpid: %d", errno);
+  // Note that we shouldn't consider ECHILD an error because
+  // the secondary zygote might have no children left to wait for.
+  if (pid < 0 && errno != ECHILD) {
+    ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
   }
 }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4f093a8..3d3e86f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2681,6 +2681,26 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+        <activity android:name="com.android.internal.app.IntentForwarderActivity"
+                android:finishOnCloseSystemDialogs="true"
+                android:theme="@style/Theme.NoDisplay"
+                android:excludeFromRecents="true"
+                android:label="@string/user_owner_label"
+                android:exported="true"
+                >
+        </activity>
+        <activity-alias android:name="com.android.internal.app.ForwardIntentToUserOwner"
+                android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+                android:icon="@drawable/personal_icon"
+                android:exported="true"
+                android:label="@string/user_owner_label">
+        </activity-alias>
+        <activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
+                android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+                android:icon="@drawable/work_icon"
+                android:exported="true"
+                android:label="@string/managed_profile_label">
+        </activity-alias>
         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
                 android:theme="@style/Theme.Holo.Dialog"
                 android:label="@string/heavy_weight_switcher_title"
diff --git a/core/res/res/drawable-hdpi/personal_icon.png b/core/res/res/drawable-hdpi/personal_icon.png
new file mode 100644
index 0000000..8d96b5e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/personal_icon.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/work_icon.png b/core/res/res/drawable-hdpi/work_icon.png
new file mode 100644
index 0000000..e90866b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/work_icon.png
Binary files differ
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 4c4d0ce..1dd4608 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -27,4 +27,7 @@
         <item>settings</item>
     </string-array>
 
-</resources>
\ No newline at end of file
+    <!-- Base "touch slop" value used by ViewConfiguration as a
+         movement threshold where scrolling should begin. -->
+    <dimen name="config_viewConfigurationTouchSlop">4dp</dimen>
+</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 57b2c01..97400b2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -454,6 +454,12 @@
     <!-- Label for the Android system components when they are shown to the user. -->
     <string name="android_system_label">Android System</string>
 
+    <!-- Label for the user owner in the intent forwarding app. -->
+    <string name="user_owner_label">Personal</string>
+
+    <!-- Label for a corporate profile in the intent forwarding app. -->
+    <string name="managed_profile_label">Work</string>
+
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_costMoney">Services that cost you money</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/tests/inputmethodtests/run_core_inputmethod_test.sh b/core/tests/inputmethodtests/run_core_inputmethod_test.sh
index b0b119b..9029ba5 100755
--- a/core/tests/inputmethodtests/run_core_inputmethod_test.sh
+++ b/core/tests/inputmethodtests/run_core_inputmethod_test.sh
@@ -21,4 +21,4 @@
   $COMMAND
 fi
 
-adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner
+adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest,android.os.InputMethodSubtypeSwitchingControllerTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
new file mode 100644
index 0000000..6d33529
--- /dev/null
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.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.os;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
+
+import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
+import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTestCase {
+    final private static String DUMMY_PACKAGE_NAME = "dymmy package name";
+    final private static String DUMMY_SETTING_ACTIVITY_NAME = "";
+    final private static boolean DUMMY_IS_AUX_IME = false;
+    final private static boolean DUMMY_FORCE_DEFAULT = false;
+    final private static int DUMMY_IS_DEFAULT_RES_ID = 0;
+    final private static String SYSTEM_LOCALE = "en_US";
+
+    private static InputMethodSubtype createDummySubtype(final String locale) {
+        final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder();
+        return builder.setSubtypeNameResId(0)
+                .setSubtypeIconResId(0)
+                .setSubtypeLocale(locale)
+                .setIsAsciiCapable(true)
+                .build();
+    }
+
+    private static void addDummyImeSubtypeListItems(List<ImeSubtypeListItem> items,
+            String imeName, String imeLabel, List<String> subtypeLocales,
+            boolean supportsSwitchingToNextInputMethod) {
+        final ResolveInfo ri = new ResolveInfo();
+        final ServiceInfo si = new ServiceInfo();
+        final ApplicationInfo ai = new ApplicationInfo();
+        ai.packageName = DUMMY_PACKAGE_NAME;
+        ai.enabled = true;
+        si.applicationInfo = ai;
+        si.enabled = true;
+        si.packageName = DUMMY_PACKAGE_NAME;
+        si.name = imeName;
+        si.exported = true;
+        si.nonLocalizedLabel = imeLabel;
+        ri.serviceInfo = si;
+        final List<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        for (String subtypeLocale : subtypeLocales) {
+            subtypes.add(createDummySubtype(subtypeLocale));
+        }
+        final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
+                DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
+                DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod);
+        for (int i = 0; i < subtypes.size(); ++i) {
+            final String subtypeLocale = subtypeLocales.get(i);
+            final InputMethodSubtype subtype = subtypes.get(i);
+            items.add(new ImeSubtypeListItem(imeName, subtypeLocale, imi, i, subtypeLocale,
+                    SYSTEM_LOCALE));
+        }
+    }
+
+    private static List<ImeSubtypeListItem> createTestData() {
+        final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>();
+        addDummyImeSubtypeListItems(items, "switchAwareLatinIme", "switchAwareLatinIme",
+                Arrays.asList("en_US", "es_US", "fr"),
+                true /* supportsSwitchingToNextInputMethod*/);
+        addDummyImeSubtypeListItems(items, "nonSwitchAwareLatinIme", "nonSwitchAwareLatinIme",
+                Arrays.asList("en_UK", "hi"),
+                false /* supportsSwitchingToNextInputMethod*/);
+        addDummyImeSubtypeListItems(items, "switchAwareJapaneseIme", "switchAwareJapaneseIme",
+                Arrays.asList("ja_JP"),
+                true /* supportsSwitchingToNextInputMethod*/);
+        addDummyImeSubtypeListItems(items, "nonSwitchAwareJapaneseIme", "nonSwitchAwareJapaneseIme",
+                Arrays.asList("ja_JP"),
+                false /* supportsSwitchingToNextInputMethod*/);
+        return items;
+    }
+
+    @SmallTest
+    public void testGetNextInputMethodImplWithNotOnlyCurrentIme() throws Exception {
+        final List<ImeSubtypeListItem> imList = createTestData();
+
+        final boolean ONLY_CURRENT_IME = false;
+        ImeSubtypeListItem currentIme;
+        ImeSubtypeListItem nextIme;
+
+        // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US"
+        currentIme = imList.get(0);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(1), nextIme);
+        // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr"
+        currentIme = imList.get(1);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(2), nextIme);
+        // "switchAwareLatinIme/fr" -> "nonSwitchAwareLatinIme/en_UK
+        currentIme = imList.get(2);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(3), nextIme);
+        // "nonSwitchAwareLatinIme/en_UK" -> "nonSwitchAwareLatinIme/hi"
+        currentIme = imList.get(3);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(4), nextIme);
+        // "nonSwitchAwareLatinIme/hi" -> "switchAwareJapaneseIme/ja_JP"
+        currentIme = imList.get(4);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(5), nextIme);
+        // "switchAwareJapaneseIme/ja_JP" -> "nonSwitchAwareJapaneseIme/ja_JP"
+        currentIme = imList.get(5);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(6), nextIme);
+        // "nonSwitchAwareJapaneseIme/ja_JP" -> "switchAwareLatinIme/en_US"
+        currentIme = imList.get(6);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(0), nextIme);
+    }
+
+    @SmallTest
+    public void testGetNextInputMethodImplWithOnlyCurrentIme() throws Exception {
+        final List<ImeSubtypeListItem> imList = createTestData();
+
+        final boolean ONLY_CURRENT_IME = true;
+        ImeSubtypeListItem currentIme;
+        ImeSubtypeListItem nextIme;
+
+        // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US"
+        currentIme = imList.get(0);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(1), nextIme);
+        // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr"
+        currentIme = imList.get(1);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(2), nextIme);
+        // "switchAwareLatinIme/fr" -> "switchAwareLatinIme/en_US"
+        currentIme = imList.get(2);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(0), nextIme);
+
+        // "nonSwitchAwareLatinIme/en_UK" -> "nonSwitchAwareLatinIme/hi"
+        currentIme = imList.get(3);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(4), nextIme);
+        // "nonSwitchAwareLatinIme/hi" -> "switchAwareLatinIme/en_UK"
+        currentIme = imList.get(4);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(3), nextIme);
+
+        // "switchAwareJapaneseIme/ja_JP" -> null
+        currentIme = imList.get(5);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertNull(nextIme);
+
+        // "nonSwitchAwareJapaneseIme/ja_JP" -> null
+        currentIme = imList.get(6);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertNull(nextIme);
+    }
+ }
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 071492d..8ea5e7e 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -253,36 +253,36 @@
     <td>Windows</td>
     <td>
   <a onclick="return onDownload(this)" id="win-studio"
-      href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-windows.exe">
-      android-studio-bundle-133.1028713-windows.exe
+      href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-windows.exe">
+      android-studio-bundle-135.1078000-windows.exe
       </a>
     </td>
-    <td>519592042 bytes</td>
-    <td>9029c18738a75830786326d62c96d557</td>
+    <td>519082997 bytes</td>
+    <td>ac69889210c4d02ee3ccc1c0f3c5cf3c</td>
   </tr>
 
   <tr>
     <td><nobr>Mac OS X</nobr></td>
     <td>
   <a onclick="return onDownload(this)" id="mac-studio"
-    href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-mac.dmg">
-    android-studio-bundle-133.1028713-mac.dmg
+    href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-mac.dmg">
+    android-studio-bundle-135.1078000-mac.dmg
     </a>
     </td>
-    <td>497595811 bytes</td>
-    <td>eb2474e6d17537ddfa535e6fe8adcf0d</td>
+    <td>495989974 bytes</td>
+    <td>8c7b1ef376b8ca206c99823d9e8fd54d</td>
   </tr>
 
   <tr>
     <td>Linux</td>
     <td>
   <a onclick="return onDownload(this)" id="linux-studio"
-    href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-linux.tgz">
-    android-studio-bundle-133.1028713-linux.tgz
+    href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-linux.tgz">
+    android-studio-bundle-135.1078000-linux.tgz
     </a>
     </td>
-    <td>522177460 bytes</td>
-    <td>cc847dd6249b3033737dabe0377c8c66</td>
+    <td>520523870 bytes</td>
+    <td>689238d5e632fd236b13f9c6d49f0cb4</td>
   </tr>
   </table>
 
@@ -430,6 +430,19 @@
 <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=""/>Android Studio v0.5.2</a> <em>(May 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+  <ul>
+    <li>See <a href="http://tools.android.com/recent">tools.android.com</a> for a full list of changes.</li>
+  </ul>
+  </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=""/>Android Studio v0.4.6</a> <em>(March 2014)</em>
   </p>
 
@@ -650,7 +663,7 @@
   if (os) {
     /* set up primary ACE download button */
     $('#download-ide-button').show();
-    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.4.6</span>"
+    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.5.2</span>"
         + "<br/> <span class='small'>for " + os + "</span>");
     $('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
 
diff --git a/docs/html/wear/images/11_bundles_A.png b/docs/html/wear/images/11_bundles_A.png
index 7199a1f..0ffc6ec 100644
--- a/docs/html/wear/images/11_bundles_A.png
+++ b/docs/html/wear/images/11_bundles_A.png
Binary files differ
diff --git a/docs/html/wear/images/11_bundles_B.png b/docs/html/wear/images/11_bundles_B.png
index bb751a2..c188d3d 100644
--- a/docs/html/wear/images/11_bundles_B.png
+++ b/docs/html/wear/images/11_bundles_B.png
Binary files differ
diff --git a/docs/html/wear/images/11_bundles_C.png b/docs/html/wear/images/11_bundles_C.png
new file mode 100644
index 0000000..de71c59
--- /dev/null
+++ b/docs/html/wear/images/11_bundles_C.png
Binary files differ
diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd
index 7f955f6..e723dab 100644
--- a/docs/html/wear/notifications/stacks.jd
+++ b/docs/html/wear/notifications/stacks.jd
@@ -2,7 +2,8 @@
 
 @jd:body
 
-<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
+<img src="{@docRoot}wear/images/11_bundles_C.png" height="154" width="273" style="float:right;margin:0 0 20px 40px"/>
+<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="clear:both;float:right;margin:0 0 20px 40px" />
 <img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
 
 <p>When creating notifications for a handheld device, you should always aggregate similar
@@ -10,7 +11,7 @@
 for received messages, you should not show more than one notification
 on a handheld device&mdash;when more than one is message is received, use a single notification
 to provide a summary such as "2 new messages."</p>
-
+<br />
 <p>However, a summary notification is less useful on an Android wearable because users
 are not able to read details from each message on the wearable (they must open your app on the
 handheld to view more information). So for the wearable device, you should
@@ -25,25 +26,50 @@
 Wear</a>.</p>
 
 
-<h2 id="AddGroup">Add Each Notification to a Group</h2>
+<h2 id="AddGroup">Create notifications in stacks</h2>
+
+<div style="float:right">
+  <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
+  <div style="width:440;height:246; padding-left:20px">
+    <object type="application/x-shockwave-flash" id="ytapiplayer" data="//www.youtube.com/v/L4LvKOTkZ7Q?enablejsapi=1&amp;playerapiid=ytplayer&amp;version=3&amp;HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1" width="440" height="246" style="visibility: visible;"><param name="allowScriptAccess" value="always"></object>
+    <script type="text/javascript">
+        var params = { allowScriptAccess: "always" };
+        var atts = { id: "ytapiplayer" };
+        swfobject.embedSWF("//www.youtube.com/v/L4LvKOTkZ7Q?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
+          "ytapiplayer", "440", "246", "8", null, null, params, atts);
+
+        // Callback used to pause/resume carousel based on video state
+        function onytplayerStateChange(newState) {
+           var isPaused = $("#pauseButton").hasClass("paused");
+           if ((newState == 1) || (newState == 3)) {
+           // if playing or buffering, pause the carousel
+             if (!isPaused) {
+                $("#pauseButton").click();
+             }
+           } else {
+           // otherwise, make sure carousel is running
+             if (isPaused) {
+                $("#pauseButton").click();
+             }
+           }
+        }
+
+        // Callback received when YouTube player loads to setup callback (above)
+        function onYouTubePlayerReady(playerId) {
+          var ytplayer = document.getElementById("ytapiplayer");
+          ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
+        }
+
+    </script>
+  </div>
+</div>
+
 
 <p>To create a stack, call <a
 href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
 <code>setGroup()</code></a> for each notification you want in the stack, passing the same
-group key. For example:</p>
+group key.</p>
 
-<pre style="clear:right">
-final static String GROUP_KEY_EMAILS = "group_key_emails";
-
-NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
-         .setContentTitle("New mail from " + sender)
-         .setContentText(subject)
-         .setSmallIcon(R.drawable.new_mail);
-
-Notification notif = new WearableNotifications.Builder(builder)
-         .setGroup(GROUP_KEY_EMAILS)
-         .build();
-</pre>
 
 <p>By default, notifications appear in the order in which you added them, with the most recent
   notification visible at the top.  You can define a specific position in the group
@@ -52,21 +78,82 @@
 <code>setGroup()</code></a>.</p>
 
 
-<h2 id="AddSummary">Add a Summary Notification</h2>
-
-<p>It's important that you still provide a summary notification that appears on handheld devices.
+<p>It's also important that you still provide a summary notification that appears on handheld devices.
 So in addition to adding each unique notification to the same stack group, also add a summary
 notification, but set its order position to be <a
 href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
 
-<pre>
-Notification summaryNotification = new WearableNotifications.Builder(builder)
-         .setGroup(GROUP_KEY_EMAILS, WearableNotifications.GROUP_ORDER_SUMMARY)
-         .build();
-</pre>
-
 <p>This notification will not appear in your stack of notifications on the wearable, but
 appears as the only notification on the handheld device.
+</p>
+
+
+<p>Here's an example that creates a stack notification for a wearable and
+a summary notification for a handset device:</p>
+
+<pre style="clear:right">
+public void onClick_button_groups () {
+    Bitmap bitmapMila = BitmapFactory.decodeResource(getResources(),
+    		R.drawable.mila128);
+
+    // Nuke all previous notifications and generate unique ids
+    NotificationManagerCompat.from(this).cancelAll();
+    int notificationId = 0;
+
+    // String to represent the group all the notifications will be a part of
+    final String GROUP_KEY_EMAILS = "group_key_messages";
+
+    // Group notification that will be visible on the phone
+    NotificationCompat.Builder builderG = new NotificationCompat.Builder(this)
+            .setContentTitle("2 Pet Notifications")
+            .setContentText("Mila and Dylan both sent messages")
+            .setSmallIcon(R.drawable.ic_launcher)
+            .setLargeIcon(bitmapMila);
+    Notification summaryNotification = new WearableNotifications
+    		.Builder(builderG)
+            .setGroup(GROUP_KEY_EMAILS, 
+            		WearableNotifications.GROUP_ORDER_SUMMARY)
+            .build();
+
+    // Separate notifications that will be visible on the watch
+    Intent viewIntent1 = new Intent(this, MainActivity.class);
+    PendingIntent viewPendingIntent1 =
+          PendingIntent.getActivity(this, notificationId+1, viewIntent1, 0);
+    NotificationCompat.Builder builder1 = new NotificationCompat.Builder(this)
+            .addAction(R.drawable.ic_action_done, "Treat Fed",
+            		viewPendingIntent1)
+            .setContentTitle("Message from Mila")
+            .setContentText("What's for dinner? "
+                            + "Can we have steak?")
+            .setSmallIcon(R.drawable.ic_launcher);
+    Notification notification1 = new WearableNotifications.Builder(builder1)
+            .setGroup(GROUP_KEY_EMAILS)
+            .build();
+
+    Intent viewIntent2 = new Intent(this, MainActivity.class);
+    PendingIntent viewPendingIntent2 =
+          PendingIntent.getActivity(this, notificationId+2, viewIntent2, 0);
+    NotificationCompat.Builder builder2 = new NotificationCompat.Builder(this)
+            .addAction(R.drawable.ic_action_done, "Water Filled",
+            		viewPendingIntent2)
+            .setContentTitle("Message from Dylan")
+            .setContentText("Can you refill our water bowl?")
+            .setSmallIcon(R.drawable.ic_launcher);
+    Notification notification2 = new WearableNotifications.Builder(builder2)
+            .setGroup(GROUP_KEY_EMAILS)
+            .build();
+
+    // Issue the group notification
+    NotificationManagerCompat notificationManager =
+    		NotificationManagerCompat.from(this);
+    notificationManager.notify(notificationId+0, summaryNotification);
+
+    // Issue the separate wear notifications
+    notificationManager.notify(notificationId+2, notification2);
+    notificationManager.notify(notificationId+1, notification1);
+}
+</pre>
+
 
 </body>
 </html>
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index df2123b..43223ec 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -691,9 +691,10 @@
     propertyAmbientShadowStrength = 25;
     propertySpotShadowStrength = 25;
 
-    propertyLightPosXScale = 0.5f;
-    propertyLightPosYScale = 0.0f;
-    propertyLightPosZScale = 1.0f;
+    propertyLightDiameter = -1.0f;
+    propertyLightPosY = -1.0f;
+    propertyLightPosZ = -1.0f;
+    propertyAmbientRatio = -1.0f;
 }
 
 void Caches::setTempProperty(const char* name, const char* value) {
@@ -706,17 +707,21 @@
         propertySpotShadowStrength = atoi(value);
         ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength);
         return;
-    } else if (!strcmp(name, "lightPosXScale")) {
-        propertyLightPosXScale = fmin(fmax(atof(value), 0.0), 1.0);
-        ALOGD("lightPos X Scale = %.2f", propertyLightPosXScale);
+    } else if (!strcmp(name, "ambientRatio")) {
+        propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0);
+        ALOGD("ambientRatio = %.2f", propertyAmbientRatio);
         return;
-    }  else if (!strcmp(name, "lightPosYScale")) {
-        propertyLightPosYScale = fmin(fmax(atof(value), 0.0), 1.0);
-        ALOGD("lightPos Y Scale = %.2f", propertyLightPosXScale);
+    } else if (!strcmp(name, "lightDiameter")) {
+        propertyLightDiameter = fmin(fmax(atof(value), 0.0), 3000.0);
+        ALOGD("lightDiameter = %.2f", propertyLightDiameter);
         return;
-    }  else if (!strcmp(name, "lightPosZScale")) {
-        propertyLightPosZScale = fmin(fmax(atof(value), 0.0), 1.0);
-        ALOGD("lightPos Z Scale = %.2f", propertyLightPosXScale);
+    }  else if (!strcmp(name, "lightPosY")) {
+        propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0);
+        ALOGD("lightPos Y = %.2f", propertyLightPosY);
+        return;
+    }  else if (!strcmp(name, "lightPosZ")) {
+        propertyLightPosZ = fmin(fmax(atof(value), 0.0), 3000.0);
+        ALOGD("lightPos Z = %.2f", propertyLightPosZ);
         return;
     }
     ALOGD("    failed");
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index ba3ccaf..2e2ee15 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -352,13 +352,10 @@
     void initTempProperties();
     void setTempProperty(const char* name, const char* value);
 
-    // These scaling factors range from 0 to 1, to scale the light position
-    // within the bound of (screenwidth, screenheight, max(screenwidth, screenheight));
-    // The default scale is (0.5, 0, 1) which put the light at
-    // (screenwidth / 2, 0, max(screenwidth, screenheight)).
-    float propertyLightPosXScale;
-    float propertyLightPosYScale;
-    float propertyLightPosZScale;
+    float propertyLightDiameter;
+    float propertyLightPosY;
+    float propertyLightPosZ;
+    float propertyAmbientRatio;
     int propertyAmbientShadowStrength;
     int propertySpotShadowStrength;
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 4569152..95fdb04 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -3291,10 +3291,8 @@
     if (mCaches.propertySpotShadowStrength > 0) {
         paint.setARGB(casterAlpha * mCaches.propertySpotShadowStrength, 0, 0, 0);
         VertexBuffer spotShadowVertexBuffer;
-        Vector3 lightPosScale(mCaches.propertyLightPosXScale,
-                mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
         VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateSpotShadow(
-                isCasterOpaque, casterPolygon, casterVertexCount, lightPosScale,
+                isCasterOpaque, casterPolygon, casterVertexCount,
                 *currentTransform(), getWidth(), getHeight(), casterBounds, localClip,
                 spotShadowVertexBuffer);
         drawVertexBuffer(vertexBufferMode, spotShadowVertexBuffer, &paint);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index dcd6bda..7a9c181 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -119,7 +119,7 @@
         mProperties = mStagingProperties;
     }
     if (mNeedsAnimatorsSync) {
-        mAnimators.reserve(mStagingAnimators.size());
+        mAnimators.resize(mStagingAnimators.size());
         std::vector< sp<RenderPropertyAnimator> >::iterator it;
         // hint: this means copy_if_not()
         it = std::remove_copy_if(mStagingAnimators.begin(), mStagingAnimators.end(),
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index ee60a63..be49aed 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -22,6 +22,7 @@
 #include <utils/Trace.h>
 
 #include "AmbientShadow.h"
+#include "Caches.h"
 #include "ShadowTessellator.h"
 #include "SpotShadow.h"
 
@@ -41,9 +42,14 @@
 
     // A bunch of parameters to tweak the shadow.
     // TODO: Allow some of these changable by debug settings or APIs.
-    const float heightFactor = 1.0f / 128;
+    float heightFactor = 1.0f / 128;
     const float geomFactor = 64;
 
+    Caches& caches = Caches::getInstance();
+    if (CC_UNLIKELY(caches.propertyAmbientRatio > 0.0f)) {
+        heightFactor *= caches.propertyAmbientRatio;
+    }
+
     Rect ambientShadowBounds(casterBounds);
     ambientShadowBounds.outset(maxZ * geomFactor * heightFactor);
 
@@ -62,16 +68,26 @@
 
 VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
         const Vector3* casterPolygon, int casterVertexCount,
-        const Vector3& lightPosScale, const mat4& receiverTransform,
+        const mat4& receiverTransform,
         int screenWidth, int screenHeight, const Rect& casterBounds,
         const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
     ATRACE_CALL();
 
+    Caches& caches = Caches::getInstance();
+
     // A bunch of parameters to tweak the shadow.
     // TODO: Allow some of these changable by debug settings or APIs.
     int maximal = max(screenWidth, screenHeight);
-    Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y,
-            maximal * lightPosScale.z);
+    Vector3 lightCenter(screenWidth * 0.5f, 0, maximal);
+
+    if (CC_UNLIKELY(caches.propertyLightPosY > 0)) {
+        lightCenter.y = - caches.propertyLightPosY; // negated since this shifts up
+    }
+    if (CC_UNLIKELY(caches.propertyLightPosZ > 0)) {
+        lightCenter.z = caches.propertyLightPosZ;
+    }
+
+
 #if DEBUG_SHADOW
     ALOGD("light center %f %f %f", lightCenter.x, lightCenter.y, lightCenter.z);
 #endif
@@ -82,9 +98,13 @@
     reverseReceiverTransform.loadInverse(receiverTransform);
     reverseReceiverTransform.mapPoint3d(lightCenter);
 
-    const float lightSize = maximal / 4;
+    float lightSize = maximal / 4;
     const int lightVertexCount = 8;
 
+    if (CC_UNLIKELY(caches.propertyLightDiameter > 0)) {
+        lightSize = caches.propertyLightDiameter;
+    }
+
     // Now light and caster are both in local space, we will check whether
     // the shadow is within the clip area.
     Rect lightRect = Rect(lightCenter.x - lightSize, lightCenter.y - lightSize,
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index 64e69bc..e5a3da1 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -73,7 +73,7 @@
 
     static VertexBufferMode tessellateSpotShadow(bool isCasterOpaque,
             const Vector3* casterPolygon, int casterVertexCount,
-            const Vector3& lightPosScale, const mat4& receiverTransform,
+            const mat4& receiverTransform,
             int screenWidth, int screenHeight, const Rect& casterBounds,
             const Rect& localClip, VertexBuffer& shadowVertexBuffer);
 
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 2dea509..1c73c05 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -1250,8 +1250,6 @@
                 }
                 if (prse.hasMatchingMediaButtonIntent(mediaIntent)) {
                     inStackIndex = index;
-                    // found it, ok to stop here
-                    break;
                 }
             }
 
@@ -1272,7 +1270,11 @@
                         mPRStack.push(prse);
                     } else {
                         // and put it after the ones with active playback
-                        mPRStack.add(lastPlayingIndex, prse);
+                        if (inStackIndex > lastPlayingIndex) {
+                            mPRStack.add(lastPlayingIndex, prse);
+                        } else {
+                            mPRStack.add(lastPlayingIndex - 1, prse);
+                        }
                     }
                 }
             }
@@ -2151,13 +2153,13 @@
                 // of this RemoteControlClient (note that it may not be in the stack)
                 for (int index = mPRStack.size()-1; index >= 0; index--) {
                     prse = mPRStack.elementAt(index);
-                    if (prse.isPlaybackActive()) {
-                        lastPlayingIndex = index;
-                    }
                     if (prse.getRccId() == rccId) {
                         inStackIndex = index;
                         prse.mPlaybackState = newState;
                     }
+                    if (prse.isPlaybackActive()) {
+                        lastPlayingIndex = index;
+                    }
                 }
 
                 if (inStackIndex != -1) {
@@ -2177,7 +2179,11 @@
                             mPRStack.push(prse);
                         } else {
                             // and put it after the ones with active playback
-                            mPRStack.add(lastPlayingIndex, prse);
+                            if (inStackIndex > lastPlayingIndex) {
+                                mPRStack.add(lastPlayingIndex, prse);
+                            } else {
+                                mPRStack.add(lastPlayingIndex - 1, prse);
+                            }
                         }
                     }
 
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index d04b1f8..a710c03 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -255,7 +255,7 @@
             env, env->FindClass("android/media/MediaCodec$BufferInfo"));
 
     jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
-    env->CallVoidMethod(bufferInfo, method, offset, size, timeUs, flags);
+    env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
 
     return OK;
 }
diff --git a/packages/InputDevices/res/raw/keyboard_layout_czech.kcm b/packages/InputDevices/res/raw/keyboard_layout_czech.kcm
index f710a8e..dc614db 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_czech.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_czech.kcm
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 #
-# Czech keyboard layout.
+# Czech (EU - qwerty) keyboard layout.
 #
 
 type OVERLAY
@@ -26,6 +26,8 @@
     label:                              ';'
     base:                               ';'
     shift:                              '\u00b0'
+    ralt:                               '\u0060'
+    shift+ralt:                         '\u007e'
 }
 
 key 1 {
@@ -38,6 +40,7 @@
 key 2 {
     label:                              '2'
     base:                               '\u011b'
+    capslock:                           '\u011a'
     shift:                              '2'
     ralt:                               '@'
 }
@@ -45,6 +48,7 @@
 key 3 {
     label:                              '3'
     base:                               '\u0161'
+    capslock:                           '\u0160'
     shift:                              '3'
     ralt:                               '#'
 }
@@ -52,6 +56,7 @@
 key 4 {
     label:                              '4'
     base:                               '\u010d'
+    capslock:                           '\u010c'
     shift:                              '4'
     ralt:                               '$'
 }
@@ -59,6 +64,7 @@
 key 5 {
     label:                              '5'
     base:                               '\u0159'
+    capslock:                           '\u0158'
     shift:                              '5'
     ralt:                               '%'
 }
@@ -66,6 +72,7 @@
 key 6 {
     label:                              '6'
     base:                               '\u017e'
+    capslock:                           '\u017d'
     shift:                              '6'
     ralt:                               '^'
 }
@@ -73,6 +80,7 @@
 key 7 {
     label:                              '7'
     base:                               '\u00fd'
+    capslock:                           '\u00dd'
     shift:                              '7'
     ralt:                               '&'
 }
@@ -80,6 +88,7 @@
 key 8 {
     label:                              '8'
     base:                               '\u00e1'
+    capslock:                           '\u00c1'
     shift:                              '8'
     ralt:                               '*'
 }
@@ -87,6 +96,7 @@
 key 9 {
     label:                              '9'
     base:                               '\u00ed'
+    capslock:                           '\u00cd'
     shift:                              '9'
     ralt:                               '('
 }
@@ -94,6 +104,7 @@
 key 0 {
     label:                              '0'
     base:                               '\u00e9'
+    capslock:                           '\u00c9'
     shift:                              '0'
     ralt:                               ')'
 }
@@ -180,6 +191,7 @@
 key LEFT_BRACKET {
     label:                              '\u00fa'
     base:                               '\u00fa'
+    capslock:                           '\u00da'
     shift:                              '/'
     ralt:                               '['
     ralt+shift:                         '{'
@@ -252,6 +264,7 @@
 key SEMICOLON {
     label:                              '\u016f'
     base:                               '\u016f'
+    capslock:                           '\u016e'
     shift:                              '"'
     ralt:                               ';'
     ralt+shift:                         ':'
@@ -261,8 +274,8 @@
     label:                              '\u00a7'
     base:                               '\u00a7'
     shift:                              '!'
-    ralt:                               '\''
-    ralt+shift:                         '"'
+    ralt:                               '\u00a4'
+    ralt+shift:                         '\u005e'
 }
 
 key BACKSLASH {
@@ -279,6 +292,8 @@
     label:                              '\\'
     base:                               '\\'
     shift:                              '|'
+    ralt:                               '\u00df'
+    shift+ralt:                         '\u02dd'
 }
 
 key Z {
@@ -330,6 +345,7 @@
     base:                               ','
     shift:                              '?'
     ralt:                               '<'
+    shift+ralt:                         '\u00d7'
 }
 
 key PERIOD {
@@ -337,6 +353,7 @@
     base:                               '.'
     shift:                              ':'
     ralt:                               '>'
+    shift+ralt:                         '\u00f7'
 }
 
 key SLASH {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm
index 0fabf02..66c1c98 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm
@@ -122,7 +122,7 @@
     base:                               'q'
     shift, capslock:                    'Q'
     ralt:                               '\u00e4'
-    shift+ralt:                         '\u00c4'
+    shift+ralt, capslock+ralt:          '\u00c4'
 }
 
 key W {
@@ -130,7 +130,7 @@
     base:                               'w'
     shift, capslock:                    'W'
     ralt:                               '\u00e5'
-    shift+ralt:                         '\u00c5'
+    shift+ralt, capslock+ralt:          '\u00c5'
 }
 
 key E {
@@ -138,7 +138,7 @@
     base:                               'e'
     shift, capslock:                    'E'
     ralt:                               '\u00e9'
-    shift+ralt:                         '\u00c9'
+    shift+ralt, capslock+ralt:          '\u00c9'
 }
 
 key R {
@@ -153,7 +153,7 @@
     base:                               't'
     shift, capslock:                    'T'
     ralt:                               '\u00fe'
-    shift+ralt:                         '\u00de'
+    shift+ralt, capslock+ralt:          '\u00de'
 }
 
 key Y {
@@ -161,7 +161,7 @@
     base:                               'y'
     shift, capslock:                    'Y'
     ralt:                               '\u00fc'
-    shift+ralt:                         '\u00dc'
+    shift+ralt, capslock+ralt:          '\u00dc'
 }
 
 key U {
@@ -169,7 +169,7 @@
     base:                               'u'
     shift, capslock:                    'U'
     ralt:                               '\u00fa'
-    shift+ralt:                         '\u00da'
+    shift+ralt, capslock+ralt:          '\u00da'
 }
 
 key I {
@@ -177,7 +177,7 @@
     base:                               'i'
     shift, capslock:                    'I'
     ralt:                               '\u00ed'
-    shift+ralt:                         '\u00cd'
+    shift+ralt, capslock+ralt:          '\u00cd'
 }
 
 key O {
@@ -185,7 +185,7 @@
     base:                               'o'
     shift, capslock:                    'O'
     ralt:                               '\u00f3'
-    shift+ralt:                         '\u00d3'
+    shift+ralt, capslock+ralt:          '\u00d3'
 }
 
 key P {
@@ -193,7 +193,7 @@
     base:                               'p'
     shift, capslock:                    'P'
     ralt:                               '\u00f6'
-    shift+ralt:                         '\u00d6'
+    shift+ralt, capslock+ralt:          '\u00d6'
 }
 
 key LEFT_BRACKET {
@@ -225,7 +225,7 @@
     base:                               'a'
     shift, capslock:                    'A'
     ralt:                               '\u00e1'
-    shift+ralt:                         '\u00c1'
+    shift+ralt, ralt+capslock:          '\u00c1'
 }
 
 key S {
@@ -241,7 +241,7 @@
     base:                               'd'
     shift, capslock:                    'D'
     ralt:                               '\u00f0'
-    shift+ralt:                         '\u00d0'
+    shift+ralt, capslock+ralt:          '\u00d0'
 }
 
 key F {
@@ -279,7 +279,7 @@
     base:                               'l'
     shift, capslock:                    'L'
     ralt:                               '\u00f8'
-    shift+ralt:                         '\u00d8'
+    shift+ralt, capslock+ralt:          '\u00d8'
 }
 
 key SEMICOLON {
@@ -313,7 +313,7 @@
     base:                               'z'
     shift, capslock:                    'Z'
     ralt:                               '\u00e6'
-    shift+ralt:                         '\u00c6'
+    shift+ralt, capslock+ralt:          '\u00c6'
 }
 
 key X {
@@ -347,7 +347,7 @@
     base:                               'n'
     shift, capslock:                    'N'
     ralt:                               '\u00f1'
-    shift+ralt:                         '\u00d1'
+    shift+ralt, capslock+ralt:          '\u00d1'
 }
 
 key M {
@@ -362,7 +362,7 @@
     base:                               ','
     shift:                              '<'
     ralt:                               '\u00e7'
-    shift+ralt:                         '\u00c7'
+    shift+ralt, capslock+ralt:          '\u00c7'
 }
 
 key PERIOD {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm b/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm
index 70c1fa4..2eb0f63 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 #
-# Slovak keyboard layout.
+# Slovak (EU - qwerty) keyboard layout.
 #
 
 type OVERLAY
@@ -26,94 +26,90 @@
     label:                              ';'
     base:                               ';'
     shift:                              '\u00b0'
-    ralt:                               '`'
-    ralt+shift:                         '~'
 }
 
 key 1 {
     label:                              '1'
     base:                               '+'
     shift:                              '1'
-    ralt:                               '!'
+    ralt:                               '~'
 }
 
 key 2 {
     label:                              '2'
     base:                               '\u013e'
     shift:                              '2'
-    ralt:                               '@'
+    ralt:                               '\u02c7'
 }
 
 key 3 {
     label:                              '3'
     base:                               '\u0161'
     shift:                              '3'
-    ralt:                               '#'
+    ralt:                               '\u0302'
 }
 
 key 4 {
     label:                              '4'
     base:                               '\u010d'
     shift:                              '4'
-    ralt:                               '$'
+    ralt:                               '\u02d8'
 }
 
 key 5 {
     label:                              '5'
     base:                               '\u0165'
     shift:                              '5'
-    ralt:                               '%'
+    ralt:                               '\u00b0'
 }
 
 key 6 {
     label:                              '6'
     base:                               '\u017e'
     shift:                              '6'
-    ralt:                               '^'
+    ralt:                               '\u02db'
 }
 
 key 7 {
     label:                              '7'
     base:                               '\u00fd'
     shift:                              '7'
-    ralt:                               '&'
+    ralt:                               '\u0300'
 }
 
 key 8 {
     label:                              '8'
     base:                               '\u00e1'
     shift:                              '8'
-    ralt:                               '*'
+    ralt:                               '\u02d9'
 }
 
 key 9 {
     label:                              '9'
     base:                               '\u00ed'
     shift:                              '9'
-    ralt:                               '('
+    ralt:                               '\u0301'
 }
 
 key 0 {
     label:                              '0'
     base:                               '\u00e9'
     shift:                              '0'
-    ralt:                               ')'
+    ralt:                               '\u02dd'
 }
 
 key MINUS {
     label:                              '='
     base:                               '='
     shift:                              '%'
-    ralt:                               '-'
-    ralt+shift:                         '_'
+    ralt:                               '\u0308'
 }
 
 key EQUALS {
     label:                              '\u00b4'
     base:                               '\u0301'
     shift:                              '\u030c'
-    ralt:                               '='
-    ralt+shift:                         '+'
+    ralt:                               '\u00b8'
 }
 
 ### ROW 2
@@ -179,22 +175,21 @@
     label:                              'P'
     base:                               'p'
     shift, capslock:                    'P'
+    ralt:                               '\''
 }
 
 key LEFT_BRACKET {
     label:                              '\u00fa'
     base:                               '\u00fa'
     shift:                              '/'
-    ralt:                               '['
-    ralt+shift:                         '{'
+    ralt:                               '\u00f7'
 }
 
 key RIGHT_BRACKET {
     label:                              '\u00e4'
     base:                               '\u00e4'
     shift:                              '('
-    ralt:                               ']'
-    ralt+shift:                         '}'
+    ralt:                               '\u00d7'
 }
 
 ### ROW 3
@@ -209,24 +204,28 @@
     label:                              'S'
     base:                               's'
     shift, capslock:                    'S'
+    ralt:                               '\u0111'
 }
 
 key D {
     label:                              'D'
     base:                               'd'
     shift, capslock:                    'D'
+    ralt:                               '\u0110'
 }
 
 key F {
     label:                              'F'
     base:                               'f'
     shift, capslock:                    'F'
+    ralt:                               '['
 }
 
 key G {
     label:                              'G'
     base:                               'g'
     shift, capslock:                    'G'
+    ralt:                               ']'
 }
 
 key H {
@@ -245,64 +244,65 @@
     label:                              'K'
     base:                               'k'
     shift, capslock:                    'K'
+    ralt:                               '\u0142'
 }
 
 key L {
     label:                              'L'
     base:                               'l'
     shift, capslock:                    'L'
+    ralt:                               '\u0141'
 }
 
 key SEMICOLON {
     label:                              '\u00f4'
     base:                               '\u00f4'
     shift:                              '"'
-    ralt:                               ';'
-    ralt+shift:                         ':'
+    ralt:                               '$'
 }
 
 key APOSTROPHE {
     label:                              '\u00a7'
     base:                               '\u00a7'
     shift:                              '!'
-    ralt:                               '\''
-    ralt+shift:                         '"'
+    ralt:                               '\u00df'
 }
 
 key BACKSLASH {
     label:                              '\u0148'
     base:                               '\u0148'
     shift:                              ')'
-    ralt:                               '\\'
-    ralt+shift:                         '|'
+    ralt:                               '\u00a4'
 }
 
 ### ROW 4
 
 key PLUS {
-    label:                              '\\'
-    base:                               '\\'
-    shift:                              '|'
-    ralt:                               '&'
-    ralt+shift:                         '*'
+    label:                              '&'
+    base:                               '&'
+    shift:                              '*'
+    ralt:                               '<'
 }
 
 key Z {
     label:                              'Z'
     base:                               'z'
     shift, capslock:                    'Z'
+    ralt:                               '>'
 }
 
 key X {
     label:                              'X'
     base:                               'x'
     shift, capslock:                    'X'
+    ralt:                               '#'
 }
 
 key C {
     label:                              'C'
     base:                               'c'
     shift, capslock:                    'C'
+    ralt:                               '&'
 }
 
 key V {
@@ -316,12 +316,14 @@
     label:                              'B'
     base:                               'b'
     shift, capslock:                    'B'
+    ralt:                               '{'
 }
 
 key N {
     label:                              'N'
     base:                               'n'
     shift, capslock:                    'N'
+    ralt:                               '}'
 }
 
 key M {
@@ -348,6 +350,5 @@
     label:                              '-'
     base:                               '-'
     shift:                              '_'
-    ralt:                               '/'
-    ralt+shift:                         '?'
+    ralt:                               '*'
 }
diff --git a/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm b/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm
index a75d154..9e20462 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm
@@ -56,12 +56,14 @@
     label:                              '4'
     base:                               '4'
     shift:                              '\u00e7'
+    ralt:                               '\u00b0'
 }
 
 key 5 {
     label:                              '5'
     base:                               '5'
     shift:                              '%'
+    ralt:                               '\u00a7'
 }
 
 key 6 {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm b/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm
index ae93f4b..7fbd1a9 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm
@@ -56,12 +56,14 @@
     label:                              '4'
     base:                               '4'
     shift:                              '\u00e7'
+    ralt:                               '\u00b0'
 }
 
 key 5 {
     label:                              '5'
     base:                               '5'
     shift:                              '%'
+    ralt:                               '\u00a7'
 }
 
 key 6 {
@@ -178,6 +180,8 @@
     label:                              '\u00fc'
     base:                               '\u00fc'
     shift:                              '\u00e8'
+    capslock:                           '\u00dc'
+    capslock+shift:                     '\u00c8'
     ralt:                               '['
 }
 
@@ -248,12 +252,16 @@
     label:                              '\u00f6'
     base:                               '\u00f6'
     shift:                              '\u00e9'
+    capslock:                           '\u00d6'
+    capslock+shift:                     '\u00c9'
 }
 
 key APOSTROPHE {
     label:                              '\u00e4'
     base:                               '\u00e4'
     shift:                              '\u00e0'
+    capslock:                           '\u00c4'
+    capslock+shift:                     '\u00c0'
     ralt:                               '{'
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 74483cc..4857adc 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -211,6 +211,7 @@
             if (mReceiver != null) {
                 unregisterReceiver(mReceiver);
             }
+            mBackground = null;
         }
 
         void updateSurfaceSize(SurfaceHolder surfaceHolder) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 72d9a52..a996c1a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -26,7 +26,7 @@
         public static final boolean Verbose = false;
 
         public static class App {
-            public static final boolean EnableTaskFiltering = true;
+            public static final boolean EnableTaskFiltering = false;
             public static final boolean EnableTaskStackClipping = false;
             public static final boolean EnableInfoPane = true;
             public static final boolean EnableSearchButton = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index a77e61d..0a8e76f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -976,8 +976,6 @@
             } else {
                 mStack.filterTasks(tv.getTask());
             }
-        } else {
-            Console.logError(getContext(), "Task Filtering TBD");
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 9c6238f..24daa4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -66,8 +66,8 @@
         }
         initializeAddedViewStates(mAnimationEvents, finalState);
         int childCount = mHostLayout.getChildCount();
+        boolean isFirstAnimatingView = true;
         for (int i = 0; i < childCount; i++) {
-            final boolean isFirstView = i == 0;
             final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
             StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
             if (viewState == null) {
@@ -80,7 +80,7 @@
                 child.setVisibility(View.VISIBLE);
             }
 
-            startPropertyAnimation(newDuration, isFirstView, child, viewState, alpha);
+            startPropertyAnimation(newDuration, isFirstAnimatingView, child, viewState, alpha);
 
             // TODO: animate clipBounds
             child.setClipBounds(null);
@@ -88,11 +88,12 @@
             if (viewState.height != currentHeigth) {
                 startHeightAnimation(newDuration, child, viewState, currentHeigth);
             }
+            isFirstAnimatingView = false;
         }
         mAnimationIsRunning = true;
     }
 
-    private void startPropertyAnimation(long newDuration, final boolean isFirstView,
+    private void startPropertyAnimation(long newDuration, final boolean hasFinishAction,
             final ExpandableView child, StackScrollState.ViewState viewState, final float alpha) {
         child.animate().setInterpolator(mFastOutSlowInInterpolator)
                 .alpha(alpha)
@@ -103,7 +104,7 @@
                     @Override
                     public void run() {
                         mAnimationIsRunning = false;
-                        if (isFirstView) {
+                        if (hasFinishAction) {
                             mHandledEvents.clear();
                             mHostLayout.onChildAnimationFinished();
                         }
@@ -128,16 +129,26 @@
         heightAnimator.start();
     }
 
+    /**
+     * Initialize the viewStates for the added children
+     *
+     * @param animationEvents the animation events who contain the added children
+     * @param finalState the final state to animate to
+     */
     private void initializeAddedViewStates(
-            ArrayList<NotificationStackScrollLayout.ChildHierarchyChangeEvent> mAnimationEvents,
+            ArrayList<NotificationStackScrollLayout.ChildHierarchyChangeEvent> animationEvents,
             StackScrollState finalState) {
-        for (NotificationStackScrollLayout.ChildHierarchyChangeEvent event: mAnimationEvents) {
+        for (NotificationStackScrollLayout.ChildHierarchyChangeEvent event: animationEvents) {
             View changingView = event.changingView;
             if (event.animationType == NotificationStackScrollLayout.ChildHierarchyChangeEvent
                     .ANIMATION_TYPE_ADD && !mHandledEvents.contains(event)) {
 
                 // This item is added, initialize it's properties.
                 StackScrollState.ViewState viewState = finalState.getViewStateForView(changingView);
+                if (viewState == null) {
+                    // The position for this child was never generated, let's continue.
+                    continue;
+                }
                 changingView.setAlpha(0);
                 changingView.setTranslationY(viewState.yTranslation);
                 changingView.setTranslationZ(viewState.zTranslation);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 62deec2..d6ecb46 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -426,29 +426,33 @@
             Slog.e(TAG,  "no geocoder provider found");
         }
 
-        // bind to fused provider
-        FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
-        FusedProxy fusedProxy = FusedProxy.createAndBind(
-                mContext,
-                mLocationHandler,
-                flpHardwareProvider.getLocationHardware(),
-                com.android.internal.R.bool.config_enableFusedLocationOverlay,
-                com.android.internal.R.string.config_fusedLocationProviderPackageName,
-                com.android.internal.R.array.config_locationProviderPackageNames);
-        if(fusedProxy == null) {
-            Slog.e(TAG, "No FusedProvider found.");
-        }
+        // bind to fused provider if supported
+        if (FlpHardwareProvider.isSupported()) {
+          FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
+          FusedProxy fusedProxy = FusedProxy.createAndBind(
+                  mContext,
+                  mLocationHandler,
+                  flpHardwareProvider.getLocationHardware(),
+                  com.android.internal.R.bool.config_enableFusedLocationOverlay,
+                  com.android.internal.R.string.config_fusedLocationProviderPackageName,
+                  com.android.internal.R.array.config_locationProviderPackageNames);
+          if(fusedProxy == null) {
+              Slog.e(TAG, "Unable to bind FusedProxy.");
+          }
 
-        // bind to geofence provider
-        GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
-                com.android.internal.R.bool.config_enableGeofenceOverlay,
-                com.android.internal.R.string.config_geofenceProviderPackageName,
-                com.android.internal.R.array.config_locationProviderPackageNames,
-                mLocationHandler,
-                gpsProvider.getGpsGeofenceProxy(),
-                flpHardwareProvider.getGeofenceHardware());
-        if (provider == null) {
-            Slog.e(TAG,  "no geofence provider found");
+          // bind to geofence provider
+          GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
+                  com.android.internal.R.bool.config_enableGeofenceOverlay,
+                  com.android.internal.R.string.config_geofenceProviderPackageName,
+                  com.android.internal.R.array.config_locationProviderPackageNames,
+                  mLocationHandler,
+                  gpsProvider.getGpsGeofenceProxy(),
+                  flpHardwareProvider.getGeofenceHardware());
+          if (provider == null) {
+              Slog.e(TAG,  "Unable to bind FLP Geofence proxy.");
+          }
+        } else {
+          Slog.e(TAG, "FLP HAL not supported.");
         }
 
         String[] testProviderStrings = resources.getStringArray(
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0c91907..9eaddbd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1017,11 +1017,11 @@
 
     static class ProcessChangeItem {
         static final int CHANGE_ACTIVITIES = 1<<0;
-        static final int CHANGE_IMPORTANCE= 1<<1;
+        static final int CHANGE_PROCESS_STATE = 1<<1;
         int changes;
         int uid;
         int pid;
-        int importance;
+        int processState;
         boolean foregroundActivities;
     }
 
@@ -3200,11 +3200,10 @@
                             observer.onForegroundActivitiesChanged(item.pid, item.uid,
                                     item.foregroundActivities);
                         }
-                        if ((item.changes&ProcessChangeItem.CHANGE_IMPORTANCE) != 0) {
-                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "IMPORTANCE CHANGED pid="
-                                    + item.pid + " uid=" + item.uid + ": " + item.importance);
-                            observer.onImportanceChanged(item.pid, item.uid,
-                                    item.importance);
+                        if ((item.changes&ProcessChangeItem.CHANGE_PROCESS_STATE) != 0) {
+                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "PROCSTATE CHANGED pid="
+                                    + item.pid + " uid=" + item.uid + ": " + item.processState);
+                            observer.onProcessStateChanged(item.pid, item.uid, item.processState);
                         }
                     }
                 } catch (RemoteException e) {
@@ -10635,6 +10634,7 @@
         int adj = app.curAdj;
         outInfo.importance = oomAdjToImportance(adj, outInfo);
         outInfo.importanceReasonCode = app.adjTypeCode;
+        outInfo.processState = app.curProcState;
     }
 
     public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
@@ -14690,7 +14690,7 @@
             app.keeping = true;
             app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
             app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
-            // System process can do UI, and when they do we want to have
+            // System processes can do UI, and when they do we want to have
             // them trim their memory after the user leaves the UI.  To
             // facilitate this, here we need to determine whether or not it
             // is currently showing UI.
@@ -15308,86 +15308,7 @@
         adj = app.modifyRawOomAdj(adj);
 
         app.curProcState = procState;
-
-        int importance = app.memImportance;
-        if (importance == 0 || adj != app.curAdj || schedGroup != app.curSchedGroup) {
-            app.curAdj = adj;
-            app.curSchedGroup = schedGroup;
-            if (!interesting) {
-                // For this reporting, if there is not something explicitly
-                // interesting in this process then we will push it to the
-                // background importance.
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-            } else if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-            } else if (adj >= ProcessList.SERVICE_B_ADJ) {
-                importance =  ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
-            } else if (adj >= ProcessList.HOME_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-            } else if (adj >= ProcessList.SERVICE_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
-            } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
-            } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
-            } else if (adj >= ProcessList.VISIBLE_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
-            } else if (adj >= ProcessList.FOREGROUND_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
-            } else {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERSISTENT;
-            }
-        }
-
-        int changes = importance != app.memImportance ? ProcessChangeItem.CHANGE_IMPORTANCE : 0;
-        if (foregroundActivities != app.foregroundActivities) {
-            changes |= ProcessChangeItem.CHANGE_ACTIVITIES;
-        }
-        if (changes != 0) {
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes);
-            app.memImportance = importance;
-            app.foregroundActivities = foregroundActivities;
-            int i = mPendingProcessChanges.size()-1;
-            ProcessChangeItem item = null;
-            while (i >= 0) {
-                item = mPendingProcessChanges.get(i);
-                if (item.pid == app.pid) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item);
-                    break;
-                }
-                i--;
-            }
-            if (i < 0) {
-                // No existing item in pending changes; need a new one.
-                final int NA = mAvailProcessChanges.size();
-                if (NA > 0) {
-                    item = mAvailProcessChanges.remove(NA-1);
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item);
-                } else {
-                    item = new ProcessChangeItem();
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item);
-                }
-                item.changes = 0;
-                item.pid = app.pid;
-                item.uid = app.info.uid;
-                if (mPendingProcessChanges.size() == 0) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG,
-                            "*** Enqueueing dispatch processes changed!");
-                    mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
-                }
-                mPendingProcessChanges.add(item);
-            }
-            item.changes |= changes;
-            item.importance = importance;
-            item.foregroundActivities = foregroundActivities;
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item "
-                    + Integer.toHexString(System.identityHashCode(item))
-                    + " " + app.toShortString() + ": changes=" + item.changes
-                    + " importance=" + item.importance
-                    + " foreground=" + item.foregroundActivities
-                    + " type=" + app.adjType + " source=" + app.adjSource
-                    + " target=" + app.adjTarget);
-        }
+        app.foregroundActivities = foregroundActivities;
 
         return app.curRawAdj;
     }
@@ -15660,7 +15581,7 @@
     }
 
     private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping,
-            ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
+            ProcessRecord TOP_APP, boolean doingAll, long now) {
         boolean success = true;
 
         if (app.curRawAdj != app.setRawAdj) {
@@ -15679,6 +15600,8 @@
             app.setRawAdj = app.curRawAdj;
         }
 
+        int changes = 0;
+
         if (app.curAdj != app.setAdj) {
             ProcessList.setOomAdj(app.pid, app.curAdj);
             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
@@ -15720,9 +15643,14 @@
                         app.curSchedGroup <= Process.THREAD_GROUP_BG_NONINTERACTIVE);
             }
         }
+        if (app.repForegroundActivities != app.foregroundActivities) {
+            app.repForegroundActivities = app.foregroundActivities;
+            changes |= ProcessChangeItem.CHANGE_ACTIVITIES;
+        }
         if (app.repProcState != app.curProcState) {
             app.repProcState = app.curProcState;
-            if (!reportingProcessState && app.thread != null) {
+            changes |= ProcessChangeItem.CHANGE_PROCESS_STATE;
+            if (app.thread != null) {
                 try {
                     if (false) {
                         //RuntimeException h = new RuntimeException("here");
@@ -15767,6 +15695,51 @@
                 app.procStateChanged = true;
             }
         }
+
+        if (changes != 0) {
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes);
+            int i = mPendingProcessChanges.size()-1;
+            ProcessChangeItem item = null;
+            while (i >= 0) {
+                item = mPendingProcessChanges.get(i);
+                if (item.pid == app.pid) {
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item);
+                    break;
+                }
+                i--;
+            }
+            if (i < 0) {
+                // No existing item in pending changes; need a new one.
+                final int NA = mAvailProcessChanges.size();
+                if (NA > 0) {
+                    item = mAvailProcessChanges.remove(NA-1);
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item);
+                } else {
+                    item = new ProcessChangeItem();
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item);
+                }
+                item.changes = 0;
+                item.pid = app.pid;
+                item.uid = app.info.uid;
+                if (mPendingProcessChanges.size() == 0) {
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG,
+                            "*** Enqueueing dispatch processes changed!");
+                    mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
+                }
+                mPendingProcessChanges.add(item);
+            }
+            item.changes |= changes;
+            item.processState = app.repProcState;
+            item.foregroundActivities = app.repForegroundActivities;
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item "
+                    + Integer.toHexString(System.identityHashCode(item))
+                    + " " + app.toShortString() + ": changes=" + item.changes
+                    + " procState=" + item.processState
+                    + " foreground=" + item.foregroundActivities
+                    + " type=" + app.adjType + " source=" + app.adjSource
+                    + " target=" + app.adjTarget);
+        }
+
         return success;
     }
 
@@ -15777,7 +15750,7 @@
     }
 
     private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
-            ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
+            ProcessRecord TOP_APP, boolean doingAll, long now) {
         if (app.thread == null) {
             return false;
         }
@@ -15786,8 +15759,7 @@
 
         computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);
 
-        return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll,
-                reportingProcessState, now);
+        return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll, now);
     }
 
     final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
@@ -15853,10 +15825,6 @@
     }
 
     final boolean updateOomAdjLocked(ProcessRecord app) {
-        return updateOomAdjLocked(app, false);
-    }
-
-    final boolean updateOomAdjLocked(ProcessRecord app, boolean doingProcessState) {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
         final boolean wasCached = app.cached;
@@ -15869,7 +15837,7 @@
         // need to do a complete oom adj.
         final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ
                 ? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
-        boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false, doingProcessState,
+        boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
                 SystemClock.uptimeMillis());
         if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
             // Changed to/from cached state, so apps after it in the LRU
@@ -16002,7 +15970,7 @@
                     }
                 }
 
-                applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now);
+                applyOomAdjLocked(app, wasKeeping, TOP_APP, true, now);
 
                 // Count the number of process types.
                 switch (app.curProcState) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index b15fa5d..9d6481a 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -503,7 +503,7 @@
                     // are already core system stuff so don't matter for this.
                     r.curApp = filter.receiverList.app;
                     filter.receiverList.app.curReceiver = r;
-                    mService.updateOomAdjLocked(r.curApp, true);
+                    mService.updateOomAdjLocked(r.curApp);
                 }
             }
             try {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index d04a6b2..8d7d300 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -77,7 +77,6 @@
     int curSchedGroup;          // Currently desired scheduling class
     int setSchedGroup;          // Last set to background scheduling class
     int trimMemoryLevel;        // Last selected memory trimming level
-    int memImportance;          // Importance constant computed from curAdj
     int curProcState = -1;      // Currently computed process state: ActivityManager.PROCESS_STATE_*
     int repProcState = -1;      // Last reported process state
     int setProcState = -1;      // Last set process state in process tracker
@@ -91,6 +90,7 @@
     boolean hasStartedServices; // Are there any started services running in this process?
     boolean foregroundServices; // Running any services that are foreground?
     boolean foregroundActivities; // Running any activities that are foreground?
+    boolean repForegroundActivities; // Last reported foreground activities.
     boolean systemNoUi;         // This is a system process, but not currently showing UI.
     boolean hasShownUi;         // Has UI been shown in this process since it was started?
     boolean pendingUiClean;     // Want to clean up resources from showing UI?
@@ -267,9 +267,10 @@
             pw.print(prefix); pw.print("persistent="); pw.print(persistent);
                     pw.print(" removed="); pw.println(removed);
         }
-        if (hasClientActivities || foregroundActivities) {
+        if (hasClientActivities || foregroundActivities || repForegroundActivities) {
             pw.print(prefix); pw.print("hasClientActivities="); pw.print(hasClientActivities);
-                    pw.print(" foregroundActivities="); pw.println(foregroundActivities);
+                    pw.print(" foregroundActivities="); pw.print(foregroundActivities);
+                    pw.print(" (rep="); pw.print(repForegroundActivities); pw.println(")");
         }
         if (hasStartedServices) {
             pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices);
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
index 79f192d..09f1c56 100644
--- a/services/core/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java
@@ -69,6 +69,7 @@
             sSingletonInstance = new FlpHardwareProvider(context);
         }
 
+        nativeInit();
         return sSingletonInstance;
     }
 
@@ -96,6 +97,7 @@
     }
 
     public static boolean isSupported() {
+        nativeInit();
         return nativeIsSupported();
     }
 
@@ -216,9 +218,9 @@
     // Core members
     private static native void nativeClassInit();
     private static native boolean nativeIsSupported();
+    private static native void nativeInit();
 
     // FlpLocationInterface members
-    private native void nativeInit();
     private native int nativeGetBatchSize();
     private native void nativeStartBatching(int requestId, FusedBatchOptions options);
     private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject);
@@ -258,12 +260,10 @@
     public static final String GEOFENCING = "Geofencing";
 
     public IFusedLocationHardware getLocationHardware() {
-        nativeInit();
         return mLocationHardware;
     }
 
     public IFusedGeofenceHardware getGeofenceHardware() {
-        nativeInit();
         return mGeofenceHardwareService;
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 855ae23..416a6b1 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -410,7 +410,7 @@
         }
 
         @Override
-        public void onImportanceChanged(int pid, int uid, int importance) {
+        public void onProcessStateChanged(int pid, int uid, int procState) {
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/ForwardingIntentFilter.java b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
new file mode 100644
index 0000000..aba796b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
@@ -0,0 +1,102 @@
+/*
+ * 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.server.pm;
+
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+import android.content.IntentFilter;
+import android.util.Log;
+import java.io.IOException;
+import android.os.UserHandle;
+
+/**
+ * The {@link PackageManagerService} maintains some {@link ForwardingIntentFilter}s for every user.
+ * If an {@link Intent} matches the {@link ForwardingIntentFilter}, then it can be forwarded to the
+ * {@link #mUserIdDest}.
+ */
+class ForwardingIntentFilter extends IntentFilter {
+    private static final String ATTR_USER_ID_DEST = "userIdDest";
+    private static final String ATTR_FILTER = "filter";
+
+    private static final String TAG = "ForwardingIntentFilter";
+
+    // If the intent matches the IntentFilter, then it can be forwarded to this userId.
+    final int mUserIdDest;
+
+    ForwardingIntentFilter(IntentFilter filter, int userIdDest) {
+        super(filter);
+        mUserIdDest = userIdDest;
+    }
+
+    public int getUserIdDest() {
+        return mUserIdDest;
+    }
+
+    ForwardingIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
+        String userIdDestString = parser.getAttributeValue(null, ATTR_USER_ID_DEST);
+        if (userIdDestString == null) {
+            String msg = "Missing element under " + TAG +": " + ATTR_USER_ID_DEST + " at " +
+                    parser.getPositionDescription();
+            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+            mUserIdDest = UserHandle.USER_NULL;
+        } else {
+            mUserIdDest = Integer.parseInt(userIdDestString);
+        }
+        int outerDepth = parser.getDepth();
+        String tagName = parser.getName();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            tagName = parser.getName();
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            } else if (type == XmlPullParser.START_TAG) {
+                if (tagName.equals(ATTR_FILTER)) {
+                    break;
+                } else {
+                    String msg = "Unknown element under " + Settings.TAG_FORWARDING_INTENT_FILTERS
+                            + ": " + tagName + " at " + parser.getPositionDescription();
+                    PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+        }
+        if (tagName.equals(ATTR_FILTER)) {
+            readFromXml(parser);
+        } else {
+            String msg = "Missing element under " + TAG + ": " + ATTR_FILTER +
+                    " at " + parser.getPositionDescription();
+            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+            XmlUtils.skipCurrentTag(parser);
+        }
+    }
+
+    public void writeToXml(XmlSerializer serializer) throws IOException {
+        serializer.attribute(null, ATTR_USER_ID_DEST, Integer.toString(mUserIdDest));
+        serializer.startTag(null, ATTR_FILTER);
+            super.writeToXml(serializer);
+        serializer.endTag(null, ATTR_FILTER);
+    }
+
+    @Override
+    public String toString() {
+        return "ForwardingIntentFilter{0x" + Integer.toHexString(System.identityHashCode(this))
+                + " " + Integer.toString(mUserIdDest) + "}";
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ForwardingIntentResolver.java b/services/core/java/com/android/server/pm/ForwardingIntentResolver.java
new file mode 100644
index 0000000..1616395
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ForwardingIntentResolver.java
@@ -0,0 +1,44 @@
+/*
+ * 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.server.pm;
+
+
+import java.io.PrintWriter;
+import com.android.server.IntentResolver;
+import java.util.List;
+
+/**
+ * Used to find a list of {@link ForwardingIntentFilter}s that match an intent.
+ */
+class ForwardingIntentResolver
+        extends IntentResolver<ForwardingIntentFilter, ForwardingIntentFilter> {
+    @Override
+    protected ForwardingIntentFilter[] newArray(int size) {
+        return new ForwardingIntentFilter[size];
+    }
+
+    @Override
+    protected boolean isPackageForFilter(String packageName, ForwardingIntentFilter filter) {
+        return false;
+    }
+
+    @Override
+    protected void sortResults(List<ForwardingIntentFilter> results) {
+        //We don't sort the results
+    }
+}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 6030d4d..ab63c9c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -16,14 +16,18 @@
 
 package com.android.server.pm;
 
+import android.app.AppGlobals;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.graphics.Rect;
@@ -170,6 +174,34 @@
     }
 
     @Override
+    public boolean isPackageEnabled(String packageName, UserHandle user)
+            throws RemoteException {
+        ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
+        long ident = Binder.clearCallingIdentity();
+        try {
+            IPackageManager pm = AppGlobals.getPackageManager();
+            PackageInfo info = pm.getPackageInfo(packageName, 0, user.getIdentifier());
+            return info != null && info.applicationInfo.enabled;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public boolean isActivityEnabled(ComponentName component, UserHandle user)
+            throws RemoteException {
+        ensureInUserProfiles(user, "Cannot check component for unrelated profile " + user);
+        long ident = Binder.clearCallingIdentity();
+        try {
+            IPackageManager pm = AppGlobals.getPackageManager();
+            ActivityInfo info = pm.getActivityInfo(component, 0, user.getIdentifier());
+            return info != null && info.isEnabled();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public void startActivityAsUser(ComponentName component, Rect sourceBounds,
             Bundle opts, UserHandle user) throws RemoteException {
         ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fffce8c..a133d42 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -28,6 +28,8 @@
 import static android.system.OsConstants.S_IXGRP;
 import static android.system.OsConstants.S_IROTH;
 import static android.system.OsConstants.S_IXOTH;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.ArrayUtils.removeInt;
 
@@ -3162,6 +3164,33 @@
         return null;
     }
 
+    /*
+     * Returns if intent can be forwarded from the userId from to dest
+     */
+    @Override
+    public boolean canForwardTo(Intent intent, String resolvedType, int userIdFrom, int userIdDest) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        List<ForwardingIntentFilter> matches =
+                getMatchingForwardingIntentFilters(intent, resolvedType, userIdFrom);
+        if (matches != null) {
+            int size = matches.size();
+            for (int i = 0; i < size; i++) {
+                if (matches.get(i).getUserIdDest() == userIdDest) return true;
+            }
+        }
+        return false;
+    }
+
+    private List<ForwardingIntentFilter> getMatchingForwardingIntentFilters(Intent intent,
+            String resolvedType, int userId) {
+        ForwardingIntentResolver fir = mSettings.mForwardingIntentResolvers.get(userId);
+        if (fir != null) {
+            return fir.queryIntent(intent, resolvedType, false, userId);
+        }
+        return null;
+    }
+
     @Override
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags, int userId) {
@@ -3190,7 +3219,38 @@
         synchronized (mPackages) {
             final String pkgName = intent.getPackage();
             if (pkgName == null) {
-                return mActivities.queryIntent(intent, resolvedType, flags, userId);
+                List<ResolveInfo> result =
+                        mActivities.queryIntent(intent, resolvedType, flags, userId);
+                // Checking if we can forward the intent to another user
+                List<ForwardingIntentFilter> fifs =
+                        getMatchingForwardingIntentFilters(intent, resolvedType, userId);
+                if (fifs != null) {
+                    ForwardingIntentFilter forwardingIntentFilterWithResult = null;
+                    HashSet<Integer> alreadyTriedUserIds = new HashSet<Integer>();
+                    for (ForwardingIntentFilter fif : fifs) {
+                        int userIdDest = fif.getUserIdDest();
+                        // Two {@link ForwardingIntentFilter}s can have the same userIdDest and
+                        // match the same an intent. For performance reasons, it is better not to
+                        // run queryIntent twice for the same userId
+                        if (!alreadyTriedUserIds.contains(userIdDest)) {
+                            List<ResolveInfo> resultUser = mActivities.queryIntent(intent,
+                                    resolvedType, flags, userIdDest);
+                            if (resultUser != null) {
+                                forwardingIntentFilterWithResult = fif;
+                                // As soon as there is a match in another user, we add the
+                                // intentForwarderActivity to the list of ResolveInfo.
+                                break;
+                            }
+                            alreadyTriedUserIds.add(userIdDest);
+                        }
+                    }
+                    if (forwardingIntentFilterWithResult != null) {
+                        ResolveInfo forwardingResolveInfo = createForwardingResolveInfo(
+                                forwardingIntentFilterWithResult, userId);
+                        result.add(forwardingResolveInfo);
+                    }
+                }
+                return result;
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
@@ -3201,6 +3261,28 @@
         }
     }
 
+    private ResolveInfo createForwardingResolveInfo(ForwardingIntentFilter fif, int userIdFrom) {
+        String className;
+        int userIdDest = fif.getUserIdDest();
+        if (userIdDest == UserHandle.USER_OWNER) {
+            className = FORWARD_INTENT_TO_USER_OWNER;
+        } else {
+            className = FORWARD_INTENT_TO_MANAGED_PROFILE;
+        }
+        ComponentName forwardingActivityComponentName = new ComponentName(
+                mAndroidApplication.packageName, className);
+        ActivityInfo forwardingActivityInfo = getActivityInfo(forwardingActivityComponentName, 0,
+                userIdFrom);
+        ResolveInfo forwardingResolveInfo = new ResolveInfo();
+        forwardingResolveInfo.activityInfo = forwardingActivityInfo;
+        forwardingResolveInfo.priority = 0;
+        forwardingResolveInfo.preferredOrder = 0;
+        forwardingResolveInfo.match = 0;
+        forwardingResolveInfo.isDefault = true;
+        forwardingResolveInfo.filter = fif;
+        return forwardingResolveInfo;
+    }
+
     @Override
     public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
@@ -11030,6 +11112,47 @@
         }
     }
 
+    /*
+     * For filters that are added with this method:
+     * if an intent for the user whose id is userIdOrig matches the filter, then this intent can
+     * also be resolved in the user whose id is userIdDest.
+     */
+    @Override
+    public void addForwardingIntentFilter(IntentFilter filter, int userIdOrig, int userIdDest) {
+        int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SYSTEM_UID) {
+            throw new SecurityException(
+                    "addForwardingIntentFilter can only be run by the system");
+        }
+        if (filter.countActions() == 0) {
+            Slog.w(TAG, "Cannot set a forwarding intent filter with no filter actions");
+            return;
+        }
+        synchronized (mPackages) {
+            mSettings.editForwardingIntentResolverLPw(userIdOrig).addFilter(
+                    new ForwardingIntentFilter(filter, userIdDest));
+            mSettings.writePackageRestrictionsLPr(userIdOrig);
+        }
+    }
+
+    @Override
+    public void clearForwardingIntentFilters(int userIdOrig) {
+        int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SYSTEM_UID) {
+            throw new SecurityException(
+                    "clearForwardingIntentFilter can only be run by the system");
+        }
+        synchronized (mPackages) {
+            ForwardingIntentResolver fir = mSettings.editForwardingIntentResolverLPw(userIdOrig);
+            HashSet<ForwardingIntentFilter> set =
+                    new HashSet<ForwardingIntentFilter>(fir.filterSet());
+            for (ForwardingIntentFilter fif : set) {
+                fir.removeFilter(fif);
+            }
+            mSettings.writePackageRestrictionsLPr(userIdOrig);
+        }
+    }
+
     @Override
     public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 678fc92..599d2a7 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -131,6 +131,8 @@
     private static final String TAG_PACKAGE = "pkg";
     private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES =
             "persistent-preferred-activities";
+    static final String TAG_FORWARDING_INTENT_FILTERS =
+            "forwarding-intent-filters";
 
     private static final String ATTR_NAME = "name";
     private static final String ATTR_USER = "user";
@@ -185,6 +187,10 @@
     final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
             new SparseArray<PersistentPreferredIntentResolver>();
 
+    // For every user, it is used to find to which other users the intent can be forwarded.
+    final SparseArray<ForwardingIntentResolver> mForwardingIntentResolvers =
+            new SparseArray<ForwardingIntentResolver>();
+
     final HashMap<String, SharedUserSetting> mSharedUsers =
             new HashMap<String, SharedUserSetting>();
     private final ArrayList<Object> mUserIds = new ArrayList<Object>();
@@ -837,6 +843,15 @@
         return ppir;
     }
 
+    ForwardingIntentResolver editForwardingIntentResolverLPw(int userId) {
+        ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId);
+        if (fir == null) {
+            fir = new ForwardingIntentResolver();
+            mForwardingIntentResolvers.put(userId, fir);
+        }
+        return fir;
+    }
+
     private File getUserPackagesStateFile(int userId) {
         return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
     }
@@ -952,6 +967,28 @@
         }
     }
 
+    private void readForwardingIntentFiltersLPw(XmlPullParser parser, int userId)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            String tagName = parser.getName();
+            if (tagName.equals(TAG_ITEM)) {
+                ForwardingIntentFilter fif = new ForwardingIntentFilter(parser);
+                editForwardingIntentResolverLPw(userId).addFilter(fif);
+            } else {
+                String msg = "Unknown element under " +  TAG_FORWARDING_INTENT_FILTERS + ": " +
+                        parser.getName();
+                PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+    }
+
     void readPackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -1080,6 +1117,8 @@
                     readPreferredActivitiesLPw(parser, userId);
                 } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
                     readPersistentPreferredActivitiesLPw(parser, userId);
+                } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) {
+                    readForwardingIntentFiltersLPw(parser, userId);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
                           + parser.getName());
@@ -1157,6 +1196,20 @@
         serializer.endTag(null, TAG_PERSISTENT_PREFERRED_ACTIVITIES);
     }
 
+    void writeForwardingIntentFiltersLPr(XmlSerializer serializer, int userId)
+            throws IllegalArgumentException, IllegalStateException, IOException {
+        serializer.startTag(null, TAG_FORWARDING_INTENT_FILTERS);
+        ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId);
+        if (fir != null) {
+            for (final ForwardingIntentFilter fif : fir.filterSet()) {
+                serializer.startTag(null, TAG_ITEM);
+                fif.writeToXml(serializer);
+                serializer.endTag(null, TAG_ITEM);
+            }
+        }
+        serializer.endTag(null, TAG_FORWARDING_INTENT_FILTERS);
+    }
+
     void writePackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1255,6 +1308,8 @@
 
             writePersistentPreferredActivitiesLPr(serializer, userId);
 
+            writeForwardingIntentFiltersLPr(serializer, userId);
+
             serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
 
             serializer.endDocument();
@@ -1872,6 +1927,10 @@
                     // TODO: check whether this is okay! as it is very
                     // similar to how preferred-activities are treated
                     readPersistentPreferredActivitiesLPw(parser, 0);
+                } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) {
+                    // TODO: check whether this is okay! as it is very
+                    // similar to how preferred-activities are treated
+                    readForwardingIntentFiltersLPw(parser, 0);
                 } else if (tagName.equals("updated-package")) {
                     readDisabledSysPackageLPw(parser);
                 } else if (tagName.equals("cleaning-package")) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index a2a49c9..9061f96 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -187,7 +187,7 @@
 
         boolean trustMayHaveChanged = false;
         for (int i = 0; i < mObsoleteAgents.size(); i++) {
-            AgentInfo info = mActiveAgents.valueAt(i);
+            AgentInfo info = mObsoleteAgents.valueAt(i);
             if (info.agent.isTrusted()) {
                 trustMayHaveChanged = true;
             }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2025771..aaa97eb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3081,6 +3081,51 @@
         }
     }
 
+    public void forwardMatchingIntents(ComponentName who, IntentFilter filter, int flags) {
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            IPackageManager pm = AppGlobals.getPackageManager();
+            long id = Binder.clearCallingIdentity();
+            try {
+                if ((flags & DevicePolicyManager.FLAG_TO_PRIMARY_USER) != 0) {
+                    pm.addForwardingIntentFilter(filter, callingUserId, UserHandle.USER_OWNER);
+                }
+                if ((flags & DevicePolicyManager.FLAG_TO_MANAGED_PROFILE) != 0) {
+                    pm.addForwardingIntentFilter(filter, UserHandle.USER_OWNER, callingUserId);
+                }
+            } catch (RemoteException re) {
+                // Shouldn't happen
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
+    public void clearForwardingIntentFilters(ComponentName who) {
+        int callingUserId = UserHandle.getCallingUserId();
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            IPackageManager pm = AppGlobals.getPackageManager();
+            long id = Binder.clearCallingIdentity();
+            try {
+                pm.clearForwardingIntentFilters(callingUserId);
+                pm.clearForwardingIntentFilters(UserHandle.USER_OWNER);
+            } catch (RemoteException re) {
+                // Shouldn't happen
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
     @Override
     public Bundle getApplicationRestrictions(ComponentName who, String packageName) {
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 25bb26e..b445b8a 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1340,7 +1340,6 @@
                                 name,
                                 locale,
                                 SourcePos(in->getPrintableSource(), block.getLineNumber()));
-                        curIsPseudolocalizable = fileIsTranslatable;
                     }
 
                     if (formatted == false16) {
@@ -1352,7 +1351,7 @@
                 curType = string16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
                 curIsStyled = true;
-                curIsPseudolocalizable = (translatable != false16);
+                curIsPseudolocalizable = fileIsTranslatable && (translatable != false16);
             } else if (strcmp16(block.getElementName(&len), drawable16.string()) == 0) {
                 curTag = &drawable16;
                 curType = drawable16;