resolved conflicts for merge of d101eb99 to lmp-mr1-dev

Change-Id: I406b6e0f5bddd0cd3f1efc3f6cddb07de4cc47d5
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index e8e7485..953a1dd 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -72,9 +72,12 @@
     CtsHostsideNetworkTestsApp \
     CtsIntentReceiverApp \
     CtsIntentSenderApp \
+    CtsLauncherAppsTests \
+    CtsLauncherAppsTestsSupport \
     CtsManagedProfileApp \
     CtsMonkeyApp \
     CtsMonkeyApp2 \
+    CtsSimpleApp \
     CtsSomeAccessibilityServices \
     CtsThemeDeviceApp \
     TestDeviceSetup \
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
new file mode 100644
index 0000000..4517ea2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsLauncherAppsTests
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml b/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml
new file mode 100644
index 0000000..a21b8c2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.launchertests">
+
+    <uses-sdk android:minSdkVersion="21"/>
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.cts.launchertests"
+                     android:label="Launcher Apps CTS Tests"/>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
new file mode 100644
index 0000000..3d44ecd
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -0,0 +1,287 @@
+/*
+ * 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.cts.launchertests;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.InstrumentationTestCase;
+import android.test.InstrumentationTestRunner;
+import android.util.Pair;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.List;
+
+/**
+ * Tests for LauncherApps service
+ */
+public class LauncherAppsTests extends InstrumentationTestCase {
+
+    public static final String SIMPLE_APP_PACKAGE = "com.android.cts.launcherapps.simpleapp";
+
+    public static final String USER_EXTRA = "user_extra";
+    public static final String PACKAGE_EXTRA = "package_extra";
+    public static final String REPLY_EXTRA = "reply_extra";
+
+    public static final int MSG_RESULT = 0;
+    public static final int MSG_CHECK_PACKAGE_ADDED = 1;
+    public static final int MSG_CHECK_PACKAGE_REMOVED = 2;
+    public static final int MSG_CHECK_PACKAGE_CHANGED = 3;
+    public static final int MSG_CHECK_NO_CALLBACK = 4;
+
+    public static final int RESULT_PASS = 1;
+    public static final int RESULT_FAIL = 2;
+    public static final int RESULT_TIMEOUT = 3;
+
+    private LauncherApps mLauncherApps;
+    private UserHandle mUser;
+    private InstrumentationTestRunner mInstrumentation;
+    private Messenger mService;
+    private Connection mConnection;
+    private Result mResult;
+    private Messenger mResultMessenger;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = (InstrumentationTestRunner) getInstrumentation();
+        Bundle arguments = mInstrumentation.getArguments();
+        UserManager userManager = (UserManager) mInstrumentation.getContext().getSystemService(
+                Context.USER_SERVICE);
+        mUser = getUserHandleArgument(userManager, "testUser", arguments);
+        mLauncherApps = (LauncherApps) mInstrumentation.getContext().getSystemService(
+                Context.LAUNCHER_APPS_SERVICE);
+
+        final Intent intent = new Intent();
+        intent.setComponent(new ComponentName("com.android.cts.launchertests.support",
+                        "com.android.cts.launchertests.support.LauncherCallbackTestsService"));
+
+        mConnection = new Connection();
+        mInstrumentation.getContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+        mConnection.waitForService();
+        mResult = new Result(Looper.getMainLooper());
+        mResultMessenger = new Messenger(mResult);
+    }
+
+    public void testGetActivitiesForUserFails() throws Exception {
+        try {
+            List<LauncherActivityInfo> activities =
+                    mLauncherApps.getActivityList(null, mUser);
+            fail("getActivities for non-profile user failed to throw exception");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+    }
+
+    public void testSimpleAppInstalledForUser() throws Exception {
+        List<LauncherActivityInfo> activities =
+                mLauncherApps.getActivityList(null, mUser);
+        // Check simple app is there.
+        boolean foundSimpleApp = false;
+        for (LauncherActivityInfo activity : activities) {
+            if (activity.getComponentName().getPackageName().equals(
+                    SIMPLE_APP_PACKAGE)) {
+                foundSimpleApp = true;
+            }
+            assertTrue(activity.getUser().equals(mUser));
+        }
+        assertTrue(foundSimpleApp);
+    }
+
+    public void testPackageAddedCallbackForUser() throws Throwable {
+        int result = sendMessageToCallbacksService(MSG_CHECK_PACKAGE_ADDED,
+                mUser, SIMPLE_APP_PACKAGE);
+        assertEquals(RESULT_PASS, result);
+    }
+
+    public void testPackageRemovedCallbackForUser() throws Throwable {
+        int result = sendMessageToCallbacksService(MSG_CHECK_PACKAGE_REMOVED,
+                mUser, SIMPLE_APP_PACKAGE);
+        assertEquals(RESULT_PASS, result);
+    }
+    public void testPackageChangedCallbackForUser() throws Throwable {
+        int result = sendMessageToCallbacksService(MSG_CHECK_PACKAGE_CHANGED,
+                mUser, SIMPLE_APP_PACKAGE);
+        assertEquals(RESULT_PASS, result);
+    }
+
+    public void testNoCallbackForUser() throws Throwable {
+        int result = sendMessageToCallbacksService(MSG_CHECK_NO_CALLBACK,
+                mUser, SIMPLE_APP_PACKAGE);
+        assertEquals(RESULT_PASS, result);
+    }
+
+    public void testLaunchNonExportActivityFails() throws Exception {
+        try {
+            mLauncherApps.startMainActivity(new ComponentName(
+                    SIMPLE_APP_PACKAGE,
+                    SIMPLE_APP_PACKAGE + ".NonExportedActivity"),
+                    mUser, null, null);
+            fail("starting non-exported activity failed to throw exception");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+    }
+
+    public void testLaunchNonExportLauncherFails() throws Exception {
+        try {
+            mLauncherApps.startMainActivity(new ComponentName(
+                    SIMPLE_APP_PACKAGE,
+                    SIMPLE_APP_PACKAGE + ".NonLauncherActivity"),
+                    mUser, null, null);
+            fail("starting non-launcher activity failed to throw exception");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+    }
+
+    public void testLaunchMainActivity() throws Exception {
+        ActivityLaunchedReceiver receiver = new ActivityLaunchedReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ActivityLaunchedReceiver.ACTIVITY_LAUNCHED_ACTION);
+        mInstrumentation.getContext().registerReceiver(receiver, filter);
+        mLauncherApps.startMainActivity(new ComponentName(
+                SIMPLE_APP_PACKAGE,
+                SIMPLE_APP_PACKAGE + ".SimpleActivity"),
+                mUser, null, null);
+        assertEquals(RESULT_PASS, receiver.waitForActivity());
+        mInstrumentation.getContext().unregisterReceiver(receiver);
+    }
+
+    private UserHandle getUserHandleArgument(UserManager userManager, String key,
+            Bundle arguments) throws Exception {
+        String serial = arguments.getString(key);
+        if (serial == null) {
+            return null;
+        }
+        int serialNo = Integer.parseInt(serial);
+        return userManager.getUserForSerialNumber(serialNo);
+    }
+
+    private class Connection implements ServiceConnection {
+        private final Semaphore mSemaphore = new Semaphore(0);
+
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            mService = new Messenger(service);
+            mSemaphore.release();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName className) {
+            mService = null;
+        }
+
+        public void waitForService() {
+            try {
+                if (mSemaphore.tryAcquire(5, TimeUnit.SECONDS)) {
+                    return;
+                }
+            } catch (InterruptedException e) {
+            }
+            fail("failed to connec to service");
+        }
+    };
+
+    private static class Result extends Handler {
+
+        private final Semaphore mSemaphore = new Semaphore(0);
+        public int result = 0;
+
+        public Result(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == MSG_RESULT) {
+                result = msg.arg1;
+                mSemaphore.release();
+            } else {
+                super.handleMessage(msg);
+            }
+        }
+
+        public int waitForResult() {
+            try {
+                if (mSemaphore.tryAcquire(5, TimeUnit.SECONDS)) {
+                    return result;
+                }
+            } catch (InterruptedException e) {
+            }
+            return RESULT_TIMEOUT;
+        }
+    }
+
+    public class ActivityLaunchedReceiver extends BroadcastReceiver {
+        public static final String ACTIVITY_LAUNCHED_ACTION =
+                "com.android.cts.launchertests.LauncherAppsTests.LAUNCHED_ACTION";
+
+        private final Semaphore mSemaphore = new Semaphore(0);
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(ACTIVITY_LAUNCHED_ACTION)) {
+                mSemaphore.release();
+            }
+        }
+
+        public int waitForActivity() {
+            try {
+                if (mSemaphore.tryAcquire(5, TimeUnit.SECONDS)) {
+                    return RESULT_PASS;
+                }
+            } catch (InterruptedException e) {
+            }
+            return RESULT_TIMEOUT;
+        }
+    }
+
+    private int sendMessageToCallbacksService(int msg, UserHandle user, String packageName)
+            throws Throwable {
+        Bundle params = new Bundle();
+        params.putParcelable(USER_EXTRA, user);
+        params.putString(PACKAGE_EXTRA, packageName);
+
+        Message message = Message.obtain(null, msg, params);
+        message.replyTo = mResultMessenger;
+
+        mService.send(message);
+
+        return mResult.waitForResult();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/TestActivity.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/TestActivity.java
new file mode 100644
index 0000000..5d62c8f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/TestActivity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.cts.launchertests;
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.lang.Override;
+
+/**
+ * A simple activity to install and launch for various users to
+ * test LauncherApps.
+ */
+public class TestActivity extends Activity {
+    public static final String USER_EXTRA = "user_extra";
+    public static final int MSG_RESULT = 0;
+    public static final int RESULT_PASS = 1;
+
+    private static final String TAG = "SimpleActivity";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.i(TAG, "Created for user " + android.os.Process.myUserHandle());
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
new file mode 100644
index 0000000..2465ef3
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsLauncherAppsTestsSupport
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/AndroidManifest.xml b/hostsidetests/devicepolicy/app/LauncherTestsSupport/AndroidManifest.xml
new file mode 100644
index 0000000..fbd049f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.launchertests.support">
+
+    <uses-sdk android:minSdkVersion="21"/>
+
+    <application>
+        <service android:name=".LauncherCallbackTestsService" >
+            <intent-filter>
+                <action android:name="com.android.cts.launchertests.support.REGISTER_CALLBACK" />
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
new file mode 100644
index 0000000..8d61496
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 The Android Open Sour *
+ * 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.cts.launchertests.support;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Service that registers for LauncherApps callbacks.
+ *
+ * Registering in a service and different process so that
+ * device side code can launch it before running client
+ * side test code.
+ */
+public class LauncherCallbackTestsService extends Service {
+
+    public static final String USER_EXTRA = "user_extra";
+    public static final String PACKAGE_EXTRA = "package_extra";
+
+    public static final int MSG_RESULT = 0;
+    public static final int MSG_CHECK_PACKAGE_ADDED = 1;
+    public static final int MSG_CHECK_PACKAGE_REMOVED = 2;
+    public static final int MSG_CHECK_PACKAGE_CHANGED = 3;
+    public static final int MSG_CHECK_NO_CALLBACK = 4;
+
+    public static final int RESULT_PASS = 1;
+    public static final int RESULT_FAIL = 2;
+
+    private static final String TAG = "LauncherCallbackTests";
+
+    private static List<Pair<String, UserHandle>> mPackagesAdded
+            = new ArrayList<Pair<String, UserHandle>>();
+    private static List<Pair<String, UserHandle>> mPackagesRemoved
+            = new ArrayList<Pair<String, UserHandle>>();
+    private static List<Pair<String, UserHandle>> mPackagesChanged
+            = new ArrayList<Pair<String, UserHandle>>();
+    private static Object mPackagesLock = new Object();
+
+    private TestCallback mCallback;
+    private final Messenger mMessenger = new Messenger(new CheckHandler());
+
+    class CheckHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            Bundle params = null;
+            if (msg.obj instanceof Bundle) {
+                params = (Bundle) (msg.obj);
+            }
+            try {
+                switch (msg.what) {
+                    case MSG_CHECK_PACKAGE_ADDED: {
+                        boolean exists = eventExists(params, mPackagesAdded);
+                        teardown();
+                        msg.replyTo.send(Message.obtain(null, MSG_RESULT,
+                                        exists ? RESULT_PASS : RESULT_FAIL, 0));
+                        break;
+                    }
+                    case MSG_CHECK_PACKAGE_REMOVED: {
+                        boolean exists = eventExists(params, mPackagesRemoved);
+                        teardown();
+                        msg.replyTo.send(Message.obtain(null, MSG_RESULT,
+                                        exists ? RESULT_PASS : RESULT_FAIL, 0));
+                        break;
+                    }
+                    case MSG_CHECK_PACKAGE_CHANGED: {
+                        boolean exists = eventExists(params, mPackagesChanged);
+                        teardown();
+                        msg.replyTo.send(Message.obtain(null, MSG_RESULT,
+                                        exists ? RESULT_PASS : RESULT_FAIL, 0));
+                        break;
+                    }
+                    case MSG_CHECK_NO_CALLBACK: {
+                        boolean exists = eventExists(params, mPackagesAdded)
+                                || eventExists(params, mPackagesRemoved)
+                                || eventExists(params, mPackagesChanged);
+                        teardown();
+                        msg.replyTo.send(Message.obtain(null, MSG_RESULT,
+                                        exists ? RESULT_FAIL : RESULT_PASS, 0));
+                        break;
+                    }
+                    default:
+                        super.handleMessage(msg);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to report test status");
+            }
+        }
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (intent == null) {
+            return START_NOT_STICKY;
+        }
+        if ("com.android.cts.launchertests.support.REGISTER_CALLBACK".equals(intent.getAction())) {
+            setup();
+        }
+        return START_STICKY;
+    }
+
+    private void setup() {
+        LauncherApps launcherApps = (LauncherApps) getSystemService(
+                Context.LAUNCHER_APPS_SERVICE);
+        synchronized (mPackagesLock) {
+            mPackagesAdded.clear();
+            mPackagesRemoved.clear();
+            mPackagesChanged.clear();
+            if (mCallback != null) {
+                launcherApps.unregisterCallback(mCallback);
+            }
+            mCallback = new TestCallback();
+            launcherApps.registerCallback(mCallback);
+        }
+    }
+
+    private void teardown() {
+        LauncherApps launcherApps = (LauncherApps) getSystemService(
+                Context.LAUNCHER_APPS_SERVICE);
+        synchronized (mPackagesLock) {
+            if (mCallback != null) {
+                launcherApps.unregisterCallback(mCallback);
+                mCallback = null;
+            }
+            mPackagesAdded.clear();
+            mPackagesRemoved.clear();
+            mPackagesChanged.clear();
+        }
+    }
+
+    private boolean eventExists(Bundle params, List<Pair<String, UserHandle>> events) {
+        UserHandle user = params.getParcelable(USER_EXTRA);
+        String packageName = params.getString(PACKAGE_EXTRA);
+        synchronized (mPackagesLock) {
+            if (events != null) {
+                for (Pair<String, UserHandle> added : events) {
+                    if (added.first.equals(packageName) && added.second.equals(user)) {
+                        Log.i(TAG, "Event exists " + packageName + " for user " + user);
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+
+    private class TestCallback extends LauncherApps.Callback {
+        public void onPackageRemoved(String packageName, UserHandle user) {
+            synchronized (mPackagesLock) {
+                mPackagesRemoved.add(new Pair<String, UserHandle>(packageName, user));
+            }
+        }
+
+        public void onPackageAdded(String packageName, UserHandle user) {
+            synchronized (mPackagesLock) {
+                mPackagesAdded.add(new Pair<String, UserHandle>(packageName, user));
+            }
+        }
+
+        public void onPackageChanged(String packageName, UserHandle user) {
+            synchronized (mPackagesLock) {
+                mPackagesChanged.add(new Pair<String, UserHandle>(packageName, user));
+            }
+        }
+
+        public void onPackagesAvailable(String[] packageNames, UserHandle user,
+                boolean replacing) {
+        }
+
+        public void onPackagesUnavailable(String[] packageNames, UserHandle user,
+                boolean replacing) {
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/Android.mk b/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
new file mode 100644
index 0000000..eae0a4f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsSimpleApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
new file mode 100644
index 0000000..848317c
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/SimpleApp/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.launcherapps.simpleapp">
+
+    <application>
+        <activity android:name=".SimpleActivity" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".NonExportedActivity">
+            android:exported="false">
+        </activity>
+        <activity android:name=".NonLauncherActivity">
+            android:exported="true">
+        </activity>
+    </application>
+
+</manifest>
+
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/NonExportedActivity.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/NonExportedActivity.java
new file mode 100644
index 0000000..4801830
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/NonExportedActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.launcherapps.simpleapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.lang.Override;
+
+/**
+ * A simple activity that isn't exported, shouldn't be launchable
+ * by LauncherApps.
+ */
+public class NonExportedActivity extends Activity {
+
+    private static final String TAG = "NonExportedActivity";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.i(TAG, "Created for user " + android.os.Process.myUserHandle());
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/NonLauncherActivity.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/NonLauncherActivity.java
new file mode 100644
index 0000000..4809020
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/NonLauncherActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.launcherapps.simpleapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.lang.Override;
+
+/**
+ * A simple activity that isn't main / category launcher, shouldn't be launchable
+ * by LauncherApps.
+ */
+public class NonLauncherActivity extends Activity {
+
+    private static final String TAG = "NonLauncherActivity";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.i(TAG, "Created for user " + android.os.Process.myUserHandle());
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java
new file mode 100644
index 0000000..1d30335
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivity.java
@@ -0,0 +1,47 @@
+/*
+ * 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.cts.launcherapps.simpleapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.lang.Override;
+
+/**
+ * A simple activity to install for various users to test LauncherApps.
+ */
+public class SimpleActivity extends Activity {
+    public static String ACTIVITY_LAUNCHED_ACTION =
+            "com.android.cts.launchertests.LauncherAppsTests.LAUNCHED_ACTION";
+
+    private static final String TAG = "SimpleActivity";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.i(TAG, "Created for user " + android.os.Process.myUserHandle());
+    }
+
+    public void onStart() {
+        super.onStart();
+        Intent reply = new Intent();
+        reply.setAction(ACTIVITY_LAUNCHED_ACTION);
+        sendBroadcast(reply);
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index cd85188..c35246d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -47,6 +47,11 @@
  */
 public class BaseDevicePolicyTest extends DeviceTestCase implements IBuildReceiver {
 
+    protected static final String MANAGED_PROFILE_PKG = "com.android.cts.managedprofile";
+    protected static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
+    protected static final String ADMIN_RECEIVER_TEST_CLASS =
+            MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
+
     private static final String RUNNER = "android.test.InstrumentationTestRunner";
 
     private static final String[] REQUIRED_DEVICE_FEATURES = new String[] {
@@ -72,6 +77,7 @@
 
     protected void installApp(String fileName)
             throws FileNotFoundException, DeviceNotAvailableException {
+        CLog.logAndDisplay(LogLevel.INFO, "Installing app " + fileName);
         String installResult = getDevice().installPackage(mCtsBuild.getTestApp(fileName), true);
         assertNull(String.format("Failed to install %s, Reason: %s", fileName, installResult),
                 installResult);
@@ -93,12 +99,15 @@
     }
 
     /** Initializes the user with the given id. This is required so that apps can run on it. */
-    protected void startUser(int userId) throws DeviceNotAvailableException {
+    protected void startUser(int userId) throws Exception {
         String command = "am start-user " + userId;
+        CLog.logAndDisplay(LogLevel.INFO, "Starting command " + command);
         String commandOutput = getDevice().executeShellCommand(command);
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
         assertTrue(commandOutput + " expected to start with \"Success:\"",
                 commandOutput.startsWith("Success:"));
+        // Wait 60 seconds for intents generated to be handled.
+        Thread.sleep(60 * 1000);
     }
 
     protected int getMaxNumberOfUsersSupported() throws DeviceNotAvailableException {
@@ -137,10 +146,13 @@
         return users;
     }
 
-    protected void removeUser(int userId) throws DeviceNotAvailableException  {
+    protected void removeUser(int userId) throws Exception  {
         String removeUserCommand = "pm remove-user " + userId;
+        CLog.logAndDisplay(LogLevel.INFO, "starting command " + removeUserCommand);
         CLog.logAndDisplay(LogLevel.INFO, "Output for command " + removeUserCommand + ": "
                 + getDevice().executeShellCommand(removeUserCommand));
+        // Wait 60 seconds for user to finish being removed.
+        Thread.sleep(60 * 1000);
     }
 
     /** Returns true if the specified tests passed. Tests are run as user owner. */
@@ -166,12 +178,19 @@
         return runDeviceTests(pkgName, testClassName, testMethodName, userId);
     }
 
-    private boolean runDeviceTests(String pkgName, @Nullable String testClassName,
+    protected boolean runDeviceTests(String pkgName, @Nullable String testClassName,
             @Nullable String testMethodName, @Nullable Integer userId)
-                    throws DeviceNotAvailableException {
-        TestRunResult runResult = (userId == null)
+            throws DeviceNotAvailableException {
+        return runDeviceTests(pkgName, testClassName, testMethodName, userId, /*params*/ null);
+    }
+
+    protected boolean runDeviceTests(String pkgName, @Nullable String testClassName,
+            @Nullable String testMethodName, @Nullable Integer userId, @Nullable String params)
+                   throws DeviceNotAvailableException {
+        TestRunResult runResult = (userId == null && params == null)
                 ? doRunTests(pkgName, testClassName, testMethodName)
-                : doRunTestsAsUser(pkgName, testClassName, testMethodName, userId);
+                : doRunTestsAsUser(pkgName, testClassName, testMethodName,
+                        userId != null ? userId : 0, params != null ? params : "");
         printTestResult(runResult);
         return !runResult.hasFailedTests() && runResult.getNumTestsInState(TestStatus.PASSED) > 0;
     }
@@ -194,7 +213,7 @@
     }
 
     private TestRunResult doRunTestsAsUser(String pkgName, @Nullable String testClassName,
-            @Nullable String testMethodName, int userId)
+            @Nullable String testMethodName, int userId, String params)
             throws DeviceNotAvailableException {
         // TODO: move this to RemoteAndroidTestRunner once it supports users. Should be straight
         // forward to add a RemoteAndroidTestRunner.setUser(userId) method. Then we can merge both
@@ -206,8 +225,8 @@
                 testsToRun.append("#" + testMethodName);
             }
         }
-        String command = "am instrument --user " + userId + " -w -r " + testsToRun + " "
-                + pkgName + "/" + RUNNER;
+        String command = "am instrument --user " + userId + " " + params + " -w -r "
+                + testsToRun + " " + pkgName + "/" + RUNNER;
         CLog.i("Running " + command);
 
         CollectingTestListener listener = new CollectingTestListener();
@@ -255,4 +274,63 @@
         }
         return true;
     }
+
+    protected int createUser() throws Exception {
+        String command ="pm create-user TestUser_"+ System.currentTimeMillis();
+        CLog.logAndDisplay(LogLevel.INFO, "Starting command " + command);
+        String commandOutput = getDevice().executeShellCommand(command);
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+
+        // Extract the id of the new user.
+        String[] tokens = commandOutput.split("\\s+");
+        assertTrue(tokens.length > 0);
+        assertEquals("Success:", tokens[0]);
+        // Wait 60 seconds for intents generated to be handled.
+        Thread.sleep(60 * 1000);
+        return Integer.parseInt(tokens[tokens.length-1]);
+    }
+
+    protected int createManagedProfile() throws DeviceNotAvailableException {
+        String command =
+                "pm create-user --profileOf 0 --managed TestProfile_" + System.currentTimeMillis();
+        CLog.logAndDisplay(LogLevel.INFO, "Starting command " + command);
+        String commandOutput = getDevice().executeShellCommand(command);
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+
+        // Extract the id of the new user.
+        String[] tokens = commandOutput.split("\\s+");
+        assertTrue(commandOutput + " expected to have format \"Success: {USER_ID}\"",
+                tokens.length > 0);
+        assertEquals(commandOutput, "Success:", tokens[0]);
+        return Integer.parseInt(tokens[tokens.length-1]);
+    }
+
+
+    protected int getUserSerialNumber(int userId) throws DeviceNotAvailableException{
+        // dumpsys user return lines like "UserInfo{0:Owner:13} serialNo=0"
+        String commandOutput = getDevice().executeShellCommand("dumpsys user");
+        String[] tokens = commandOutput.split("\\n");
+        for (String token : tokens) {
+            token = token.trim();
+            if (token.contains("UserInfo{" + userId + ":")) {
+                String[] split = token.split("serialNo=");
+                assertTrue(split.length == 2);
+                int serialNumber = Integer.parseInt(split[1]);
+                CLog.logAndDisplay(LogLevel.INFO, "Serial number of user " + userId + ": "
+                        + serialNumber);
+                return serialNumber;
+            }
+        }
+        fail("Couldn't find user " + userId);
+        return -1;
+    }
+
+    protected void setProfileOwner(String componentName, int userId)
+            throws DeviceNotAvailableException {
+        String command = "dpm set-profile-owner '" + componentName + "' " + userId;
+        String commandOutput = getDevice().executeShellCommand(command);
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
+        assertTrue(commandOutput + " expected to start with \"Success:\"",
+                commandOutput.startsWith("Success:"));
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseLauncherAppsTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseLauncherAppsTest.java
new file mode 100644
index 0000000..dec8bd2
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseLauncherAppsTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 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.cts.devicepolicy;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.log.LogUtil.CLog;
+
+/**
+ * Common code for the various LauncherApps tests.
+ */
+public class BaseLauncherAppsTest extends BaseDevicePolicyTest {
+
+    protected static final String SIMPLE_APP_PKG = "com.android.cts.launcherapps.simpleapp";
+    protected static final String SIMPLE_APP_APK = "CtsSimpleApp.apk";
+    protected static final String LAUNCHER_TESTS_PKG = "com.android.cts.launchertests";
+    protected static final String LAUNCHER_TESTS_CLASS = LAUNCHER_TESTS_PKG + ".LauncherAppsTests";
+    private static final String LAUNCHER_TESTS_APK = "CtsLauncherAppsTests.apk";
+    private static final String LAUNCHER_TESTS_SUPPORT_PKG =
+            "com.android.cts.launchertests.support";
+    private static final String LAUNCHER_TESTS_SUPPORT_APK = "CtsLauncherAppsTestsSupport.apk";
+
+    protected void installTestApps() throws Exception {
+        uninstallTestApps();
+        installApp(LAUNCHER_TESTS_APK);
+        installApp(LAUNCHER_TESTS_SUPPORT_APK);
+    }
+
+    protected void uninstallTestApps() throws Exception {
+        getDevice().uninstallPackage(LAUNCHER_TESTS_PKG);
+        getDevice().uninstallPackage(LAUNCHER_TESTS_SUPPORT_PKG);
+        getDevice().uninstallPackage(SIMPLE_APP_PKG);
+    }
+
+    protected void removeTestUsers() throws Exception {
+        for (int userId : listUsers()) {
+            if (userId != 0) {
+                removeUser(userId);
+            }
+        }
+    }
+
+    protected void startCallbackService() throws Exception {
+        String command = "am startservice --user 0 "
+                + "-a " + LAUNCHER_TESTS_SUPPORT_PKG + ".REGISTER_CALLBACK "
+                + LAUNCHER_TESTS_SUPPORT_PKG + "/.LauncherCallbackTestsService";
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": "
+              + getDevice().executeShellCommand(command));
+
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
new file mode 100644
index 0000000..0af38a4
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.cts.devicepolicy;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+
+/**
+ * Set of tests for LauncherApps attempting to access a non-profiles
+ * apps.
+ */
+public class LauncherAppsMultiUserTest extends BaseLauncherAppsTest {
+
+    private int mSecondaryUserId;
+    private int mSecondaryUserSerialNumber;
+
+    private boolean mMultiUserSupported;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // We need multi user to be supported in order to create a secondary user
+        // and api level 21 to support LauncherApps
+        mMultiUserSupported = getMaxNumberOfUsersSupported() > 1 && getDevice().getApiLevel() >= 21;
+
+        if (mMultiUserSupported) {
+            removeTestUsers();
+            installTestApps();
+            // Create a secondary user.
+            mSecondaryUserId = createUser();
+            mSecondaryUserSerialNumber = getUserSerialNumber(mSecondaryUserId);
+            startUser(mSecondaryUserId);
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mMultiUserSupported) {
+            removeUser(mSecondaryUserId);
+            uninstallTestApps();
+        }
+        super.tearDown();
+    }
+
+    public void testGetActivitiesForNonProfileFails() throws Exception {
+        if (!mMultiUserSupported) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        try {
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS,
+                    "testGetActivitiesForUserFails",
+                            0, "-e testUser " + mSecondaryUserSerialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testNoLauncherCallbackPackageAddedSecondaryUser() throws Exception {
+        if (!mMultiUserSupported) {
+            return;
+        }
+        startCallbackService();
+        installApp(SIMPLE_APP_APK);
+        try {
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS,
+                            "testNoCallbackForUser",
+                            0, "-e testUser " + mSecondaryUserSerialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
new file mode 100644
index 0000000..f8c2e7d
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.cts.devicepolicy;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+
+/**
+ * Set of tests for LauncherApps with managed profiles.
+ */
+public class LauncherAppsProfileTest extends BaseLauncherAppsTest {
+
+    private int mProfileUserId;
+    private int mProfileSerialNumber;
+    private int mMainUserSerialNumber;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // We need multi user to be supported in order to create a profile of the user owner.
+        mHasFeature = mHasFeature && (getMaxNumberOfUsersSupported() > 1);
+
+        if (mHasFeature) {
+            removeTestUsers();
+            installTestApps();
+            // Create a managed profile
+            mProfileUserId = createManagedProfile();
+            installApp(MANAGED_PROFILE_APK);
+            setProfileOwner(MANAGED_PROFILE_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mProfileUserId);
+            mProfileSerialNumber = getUserSerialNumber(mProfileUserId);
+            mMainUserSerialNumber = getUserSerialNumber(0);
+            startUser(mProfileUserId);
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mHasFeature) {
+            removeUser(mProfileUserId);
+            uninstallTestApps();
+            getDevice().uninstallPackage(MANAGED_PROFILE_PKG);
+        }
+        super.tearDown();
+    }
+
+    public void testGetActivitiesWithProfile() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        // Install app for all users.
+        installApp(SIMPLE_APP_APK);
+        try {
+            // Run tests to check SimpleApp exists in both profile and main user.
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS,
+                    "testSimpleAppInstalledForUser",
+                            0, "-e testUser " + mProfileSerialNumber));
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_PKG + ".LauncherAppsTests", "testSimpleAppInstalledForUser",
+                            0, "-e testUser " + mMainUserSerialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testLauncherCallbackPackageAddedProfile() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        startCallbackService();
+        installApp(SIMPLE_APP_APK);
+        try {
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS,
+                            "testPackageAddedCallbackForUser",
+                            0, "-e testUser " + mProfileSerialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testLauncherCallbackPackageRemovedProfile() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        try {
+            startCallbackService();
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS,
+                            "testPackageRemovedCallbackForUser",
+                            0, "-e testUser " + mProfileSerialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testLauncherCallbackPackageChangedProfile() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        try {
+            startCallbackService();
+            installApp(SIMPLE_APP_APK);
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS,
+                            "testPackageChangedCallbackForUser",
+                            0, "-e testUser " + mProfileSerialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java
new file mode 100644
index 0000000..32be962
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.cts.devicepolicy;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+
+/**
+ * Set of tests for LauncherApps with managed profiles.
+ */
+public class LauncherAppsSingleUserTest extends BaseLauncherAppsTest {
+
+    private boolean mHasLauncherApps;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mHasLauncherApps = getDevice().getApiLevel() >= 21;
+
+        if (mHasLauncherApps) {
+            installTestApps();
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mHasLauncherApps) {
+            uninstallTestApps();
+        }
+        super.tearDown();
+    }
+
+    public void testInstallAppMainUser() throws Exception {
+        if (!mHasLauncherApps) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        try {
+            int serialNumber = getUserSerialNumber(0);
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS, "testSimpleAppInstalledForUser",
+                            0, "-e testUser " + serialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testLauncherCallbackPackageAddedMainUser() throws Exception {
+        if (!mHasLauncherApps) {
+            return;
+        }
+        startCallbackService();
+        installApp(SIMPLE_APP_APK);
+        try {
+            int serialNumber = getUserSerialNumber(0);
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS,
+                            "testPackageAddedCallbackForUser",
+                            0, "-e testUser " + serialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testLauncherCallbackPackageRemovedMainUser() throws Exception {
+        if (!mHasLauncherApps) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        try {
+            startCallbackService();
+            int serialNumber = getUserSerialNumber(0);
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS,
+                            "testPackageRemovedCallbackForUser",
+                            0, "-e testUser " + serialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testLauncherCallbackPackageChangedMainUser() throws Exception {
+        if (!mHasLauncherApps) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        try {
+            startCallbackService();
+            int serialNumber = getUserSerialNumber(0);
+            installApp(SIMPLE_APP_APK);
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS,
+                            "testPackageChangedCallbackForUser",
+                            0, "-e testUser " + serialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testLauncherNonExportedAppFails() throws Exception {
+        if (!mHasLauncherApps) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        try {
+            int serialNumber = getUserSerialNumber(0);
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS, "testLaunchNonExportActivityFails",
+                            0, "-e testUser " + serialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testLaunchNonExportActivityFails() throws Exception {
+        if (!mHasLauncherApps) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        try {
+            int serialNumber = getUserSerialNumber(0);
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS, "testLaunchNonExportLauncherFails",
+                            0, "-e testUser " + serialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+
+    public void testLaunchMainActivity() throws Exception {
+        if (!mHasLauncherApps) {
+            return;
+        }
+        installApp(SIMPLE_APP_APK);
+        try {
+            int serialNumber = getUserSerialNumber(0);
+            assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
+                    LAUNCHER_TESTS_CLASS, "testLaunchMainActivity",
+                            0, "-e testUser " + serialNumber));
+        } finally {
+            getDevice().uninstallPackage(SIMPLE_APP_PKG);
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index d829314..2ef7cad 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -245,27 +245,4 @@
                 "Output for command " + adbCommand + ": " + commandOutput);
         return commandOutput;
     }
-
-    private int createManagedProfile() throws DeviceNotAvailableException {
-        String command =
-                "pm create-user --profileOf 0 --managed TestProfile_" + System.currentTimeMillis();
-        String commandOutput = getDevice().executeShellCommand(command);
-        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
-
-        // Extract the id of the new user.
-        String[] tokens = commandOutput.split("\\s+");
-        assertTrue(commandOutput + " expected to have format \"Success: {USER_ID}\"",
-                tokens.length > 0);
-        assertEquals(commandOutput, "Success:", tokens[0]);
-        return Integer.parseInt(tokens[tokens.length-1]);
-    }
-
-    private void setProfileOwner(String componentName, int userId)
-            throws DeviceNotAvailableException {
-        String command = "dpm set-profile-owner '" + componentName + "' " + userId;
-        String commandOutput = getDevice().executeShellCommand(command);
-        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": " + commandOutput);
-        assertTrue(commandOutput + " expected to start with \"Success:\"",
-                commandOutput.startsWith("Success:"));
-    }
 }
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index c71eed2..3b2e3f0 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -131,6 +131,24 @@
   bug: 17508787
 },
 {
+  description: "New tests recently added for Android Enterprise. To be moved out of CTS-staging as soon as they show that they are stable",
+  names: [
+    "com.android.cts.devicepolicy.LauncherAppsMultiUserTest#testGetActivitiesForNonProfileFails",
+    "com.android.cts.devicepolicy.LauncherAppsMultiUserTest#testNoLauncherCallbackPackageAddedSecondaryUser",
+    "com.android.cts.devicepolicy.LauncherAppsProfileTest#testGetActivitiesWithProfile",
+    "com.android.cts.devicepolicy.LauncherAppsProfileTest#testLauncherCallbackPackageAddedProfile",
+    "com.android.cts.devicepolicy.LauncherAppsProfileTest#testLauncherCallbackPackageRemovedProfile",
+    "com.android.cts.devicepolicy.LauncherAppsProfileTest#testLauncherCallbackPackageChangedProfile",
+    "com.android.cts.devicepolicy.LauncherAppsSingleUserTest#testInstallAppMainUser",
+    "com.android.cts.devicepolicy.LauncherAppsSingleUserTest#testLauncherCallbackPackageAddedMainUser",
+    "com.android.cts.devicepolicy.LauncherAppsSingleUserTest#testLauncherCallbackPackageRemovedMainUser",
+    "com.android.cts.devicepolicy.LauncherAppsSingleUserTest#testLauncherCallbackPackageChangedMainUser",
+    "com.android.cts.devicepolicy.LauncherAppsSingleUserTest#testLauncherNonExportedAppFails",
+    "com.android.cts.devicepolicy.LauncherAppsSingleUserTest#testLaunchNonExportActivityFails",
+    "com.android.cts.devicepolicy.LauncherAppsSingleUserTest#testLaunchMainActivity"
+  ]
+},
+{
   description: "This test failed on devices that use effect off loading. In addition it uses hidden apis",
   names: [
     "android.media.cts.AudioEffectTest#test1_1ConstructorFromUuid"