Merge "Fix cts test in DumpsysHostTest#testBatteryStatsOutput" into mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index f743fb2..4d30dda 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -111,6 +111,7 @@
     CtsVoiceInteractionService \
     CtsVoiceInteractionApp \
     CtsVoiceSettingsService \
+    CtsWidgetProviderApp \
     $(cts_account_support_packages) \
     $(cts_security_apps_list) \
     $(cts_security_keysets_list)
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index e03ebdc..8e27e72 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -72,7 +72,7 @@
                 <action android:name="com.android.cts.managedprofile.ACTION_TEST_ALL_ACTIVITY" />
             </intent-filter>
         </activity>
-        <activity android:name=".UserRestrictionActivity" >
+        <activity android:name=".SetPolicyActivity" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT"/>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetPrimaryUserTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetPrimaryUserTest.java
new file mode 100644
index 0000000..bb1640b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetPrimaryUserTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.managedprofile;
+
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+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.test.AndroidTestCase;
+import android.util.Log;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class contains tests for cross profile widget providers that are run on the primary users.
+ * The tests connect to a {@link android.appwidget.AppWidgetHost} and check whether the cross
+ * cross-profile widget can / cannot be found from the primary user.
+ * The tests cannot be run independently, but are part of one hostside test.
+ */
+public class CrossProfileWidgetPrimaryUserTest extends AndroidTestCase {
+    private static final String TAG = "CrossProfileWidgetPrimaryUserTest";
+
+    private static final int MSG_RESULT = 0;
+    private static final int MSG_PROVIDER_PRESENT = 1;
+    private static final int MSG_PROVIDER_UPDATES = 2;
+
+    private static final int RESULT_UNKNOWN = 0;
+    private static final int RESULT_PRESENT = 1;
+    private static final int RESULT_NOTPRESENT = 2;
+    private static final int RESULT_INTERRUPTED = 3;
+    private static final int RESULT_TIMEOUT = 4;
+
+    private static final String PACKAGE_EXTRA = "package-extra";
+
+    private Messenger mService;
+    private Connection mConnection;
+    private Result mResult;
+    private Messenger mResultMessenger;
+
+    @Override
+    protected void setUp() throws Exception {
+        final Intent intent = new Intent();
+        intent.setComponent(new ComponentName(CrossProfileWidgetTest.WIDGET_PROVIDER_PKG,
+                CrossProfileWidgetTest.WIDGET_PROVIDER_PKG + ".SimpleAppWidgetHostService"));
+        mConnection = new Connection();
+        getContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+        mConnection.waitForService();
+        mResult = new Result(Looper.getMainLooper());
+        mResultMessenger = new Messenger(mResult);
+    }
+
+    public void testHasCrossProfileWidgetProvider_false() throws Exception {
+        int result = sendMessageToCallbacksService(MSG_PROVIDER_PRESENT,
+                CrossProfileWidgetTest.WIDGET_PROVIDER_PKG);
+        assertEquals(RESULT_NOTPRESENT, result);
+    }
+
+    public void testHostReceivesWidgetUpdates_false() throws Exception {
+        int result = sendMessageToCallbacksService(MSG_PROVIDER_UPDATES,
+                CrossProfileWidgetTest.WIDGET_PROVIDER_PKG);
+        assertEquals(RESULT_NOTPRESENT, result);
+    }
+
+    public void testHasCrossProfileWidgetProvider_true() throws Exception {
+        int result = sendMessageToCallbacksService(MSG_PROVIDER_PRESENT,
+                CrossProfileWidgetTest.WIDGET_PROVIDER_PKG);
+        assertEquals(RESULT_PRESENT, result);
+    }
+
+    public void testHostReceivesWidgetUpdates_true() throws Exception {
+        int result = sendMessageToCallbacksService(MSG_PROVIDER_UPDATES,
+                CrossProfileWidgetTest.WIDGET_PROVIDER_PKG);
+        assertEquals(RESULT_PRESENT, result);
+    }
+
+    private int sendMessageToCallbacksService(int msg, String packageName)
+            throws Exception {
+        Bundle params = new Bundle();
+        params.putString(PACKAGE_EXTRA, packageName);
+
+        Message message = Message.obtain(null, msg, params);
+        message.replyTo = mResultMessenger;
+
+        mService.send(message);
+
+        return mResult.waitForResult();
+    }
+
+    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(120, TimeUnit.SECONDS)) {
+                    return result;
+                }
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Interrupted when talking to service", e);
+            }
+            return RESULT_TIMEOUT;
+        }
+    }
+
+    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) {
+                Log.e(TAG, "Interrupted when connecting to service", e);
+            }
+            fail("failed to connect to service");
+        }
+    };
+
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetTest.java
new file mode 100644
index 0000000..085d56f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileWidgetTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.managedprofile;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class contains tests for cross profile widget providers that are run on the managed
+ * profile. Policies are set using {@link SetPolicyActivity} and then verified in these tests.
+ * The tests cannot be run independently, but are part of one hostside test.
+ */
+public class CrossProfileWidgetTest extends BaseManagedProfileTest {
+    static final String WIDGET_PROVIDER_PKG = "com.android.cts.widgetprovider";
+
+    private AppWidgetManager mAppWidgetManager;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        mAppWidgetManager = (AppWidgetManager) mContext.getSystemService(Context.APPWIDGET_SERVICE);
+    }
+
+    /**
+     * This test checks that the widget provider was successfully whitelisted and verifies that
+     * if was added successfully and can be found inside the profile.
+     */
+    public void testCrossProfileWidgetProviderAdded() {
+        List<String> providers = mDevicePolicyManager.getCrossProfileWidgetProviders(
+                ADMIN_RECEIVER_COMPONENT);
+        assertEquals(1, providers.size());
+        assertTrue(providers.contains(WIDGET_PROVIDER_PKG));
+        // check that widget can be found inside the profile
+        assertTrue(containsWidgetProviderPkg(mAppWidgetManager.getInstalledProviders()));
+    }
+
+    /**
+     * This test verifies that the widget provider was successfully removed from the whitelist.
+     */
+    public void testCrossProfileWidgetProviderRemoved() {
+        List<String> providers = mDevicePolicyManager.getCrossProfileWidgetProviders(
+                ADMIN_RECEIVER_COMPONENT);
+        assertTrue(providers.isEmpty());
+        // check that widget can still be found inside the profile
+        // This does not currently work correctly: http://b/issues/21180997
+        // assertTrue(containsWidgetProviderPkg(mAppWidgetManager.getInstalledProviders()));
+    }
+
+    private boolean containsWidgetProviderPkg(List<AppWidgetProviderInfo> widgets) {
+        for (AppWidgetProviderInfo widget : widgets) {
+            if (WIDGET_PROVIDER_PKG.equals(widget.provider.getPackageName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserRestrictionActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SetPolicyActivity.java
similarity index 60%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserRestrictionActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SetPolicyActivity.java
index e8decf8..f59363b 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserRestrictionActivity.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/SetPolicyActivity.java
@@ -28,15 +28,18 @@
 /**
  * Simple activity that adds or clears a user restriction depending on the value of the extras.
  */
-public class UserRestrictionActivity extends Activity {
+public class SetPolicyActivity extends Activity {
 
-    private static final String TAG = UserRestrictionActivity.class.getName();
+    private static final String TAG = SetPolicyActivity.class.getName();
 
     private static final String EXTRA_RESTRICTION_KEY = "extra-restriction-key";
+    private static final String EXTRA_PACKAGE_NAME = "extra-package-name";
     private static final String EXTRA_COMMAND = "extra-command";
 
-    private static final String ADD_COMMAND = "add-restriction";
-    private static final String CLEAR_COMMAND = "clear-restriction";
+    private static final String ADD_RESTRICTION_COMMAND = "add-restriction";
+    private static final String CLEAR_RESTRICTION_COMMAND = "clear-restriction";
+    private static final String ADD_CROSS_PROFILE_WIDGET_COMMAND = "add-cross-profile-widget";
+    private static final String REMOVE_CROSS_PROFILE_WIDGET_COMMAND = "remove-cross-profile-widget";
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -62,19 +65,32 @@
     private void handleIntent(Intent intent) {
         DevicePolicyManager dpm = (DevicePolicyManager)
                 getSystemService(Context.DEVICE_POLICY_SERVICE);
-        String restrictionKey = intent.getStringExtra(EXTRA_RESTRICTION_KEY);
         String command = intent.getStringExtra(EXTRA_COMMAND);
-        Log.i(TAG, "Command: \"" + command + "\". Restriction: \"" + restrictionKey + "\"");
+        Log.i(TAG, "Command: \"" + command);
 
-        if (ADD_COMMAND.equals(command)) {
+        if (ADD_RESTRICTION_COMMAND.equals(command)) {
+            String restrictionKey = intent.getStringExtra(EXTRA_RESTRICTION_KEY);
             dpm.addUserRestriction(BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
             Log.i(TAG, "Added user restriction " + restrictionKey
                     + " for user " + Process.myUserHandle());
-        } else if (CLEAR_COMMAND.equals(command)) {
+        } else if (CLEAR_RESTRICTION_COMMAND.equals(command)) {
+            String restrictionKey = intent.getStringExtra(EXTRA_RESTRICTION_KEY);
             dpm.clearUserRestriction(
                     BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT, restrictionKey);
             Log.i(TAG, "Cleared user restriction " + restrictionKey
                     + " for user " + Process.myUserHandle());
+        } else if (ADD_CROSS_PROFILE_WIDGET_COMMAND.equals(command)) {
+            String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
+            dpm.addCrossProfileWidgetProvider(BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT,
+                    packageName);
+            Log.i(TAG, "Added cross-profile widget provider for package:" + packageName
+                    + " for user " + Process.myUserHandle());
+        } else if (REMOVE_CROSS_PROFILE_WIDGET_COMMAND.equals(command)) {
+            String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
+            dpm.removeCrossProfileWidgetProvider(BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT,
+                    packageName);
+            Log.i(TAG, "Removed cross-profile widget provider for package:" + packageName
+                    + " for user " + Process.myUserHandle());
         } else {
             Log.e(TAG, "Invalid command: " + command);
         }
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk b/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
new file mode 100644
index 0000000..c0e35fa
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
@@ -0,0 +1,29 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsWidgetProviderApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/AndroidManifest.xml b/hostsidetests/devicepolicy/app/WidgetProvider/AndroidManifest.xml
new file mode 100644
index 0000000..77246b5
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.widgetprovider">
+
+    <uses-permission android:name="android.permission.BIND_APPWIDGET"/>
+
+    <application>
+        <receiver android:name="SimpleWidgetProvider" >
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+            </intent-filter>
+            <meta-data android:name="android.appwidget.provider"
+                       android:resource="@xml/simple_widget_provider_info" />
+        </receiver>
+        <service android:name=".SimpleAppWidgetHostService" >
+            <intent-filter>
+                <action android:name="com.android.cts.widgetprovider.REGISTER_CALLBACK" />
+            </intent-filter>
+        </service>
+    </application>
+
+</manifest>
+
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/res/layout/simple_widget.xml b/hostsidetests/devicepolicy/app/WidgetProvider/res/layout/simple_widget.xml
new file mode 100644
index 0000000..338c57a
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/res/layout/simple_widget.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:padding="10dip">
+
+    <ImageView
+        android:id="@+id/pkg_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"/>
+
+    <TextView
+        android:id="@+id/pkg_name"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_centerVertical="true"
+        android:paddingLeft="10dip"
+        android:layout_toRightOf="@id/pkg_icon"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/res/xml/simple_widget_provider_info.xml b/hostsidetests/devicepolicy/app/WidgetProvider/res/xml/simple_widget_provider_info.xml
new file mode 100644
index 0000000..8a002d2
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/res/xml/simple_widget_provider_info.xml
@@ -0,0 +1,20 @@
+<!-- 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.
+-->
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+    android:minWidth="40dp"
+    android:minHeight="40dp"
+    android:resizeMode="horizontal|vertical"
+    android:widgetCategory="home_screen">
+</appwidget-provider>
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/src/com/android/cts/widgetprovider/SimpleAppWidgetHostService.java b/hostsidetests/devicepolicy/app/WidgetProvider/src/com/android/cts/widgetprovider/SimpleAppWidgetHostService.java
new file mode 100644
index 0000000..b5b6003
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/src/com/android/cts/widgetprovider/SimpleAppWidgetHostService.java
@@ -0,0 +1,246 @@
+/*
+ * 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.widgetprovider;
+
+import android.app.Service;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Service that acts as AppWidgetHost that listens to onProvidersChanged callbacks and updates the
+ * internally stored list of profile widgets. The service reacts to messages sent from the device
+ * side tests and returns whether the expected widget provider is currently present or not.
+ */
+public class SimpleAppWidgetHostService extends Service {
+    private static final String TAG = "SimpleAppWidgetHostService";
+
+    private static final int MSG_RESULT = 0;
+    private static final int MSG_PROVIDER_PRESENT = 1;
+    private static final int MSG_PROVIDER_UPDATES = 2;
+
+    private static final int RESULT_UNKNOWN = 0;
+    private static final int RESULT_PRESENT = 1;
+    private static final int RESULT_NOT_PRESENT = 2;
+    private static final int RESULT_INTERRUPTED = 3;
+    private static final int RESULT_TIMEOUT = 4;
+
+    public static final String USER_EXTRA = "user-extra";
+    public static final String PACKAGE_EXTRA = "package-extra";
+    public static final String REPLY_EXTRA = "reply-extra";
+
+    private AppWidgetManager mAppWidgetManager;
+    private SimpleAppWidgetHost mAppWidgetHost;
+    private SimpleAppWidgetHostView mAppWidgetHostView;
+    private int mAppWidgetId;
+    private Messenger mMessenger;
+    private UserHandle mUserHandle;
+    private Semaphore mWidgetUpdateSemaphore = new Semaphore(0);
+    private RemoteViews mRemoteViews;
+
+    class CheckHandler extends Handler {
+        public CheckHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            Bundle params = null;
+            if (msg.obj instanceof Bundle) {
+                params = (Bundle) (msg.obj);
+            }
+            try {
+                switch (msg.what) {
+                    case MSG_PROVIDER_PRESENT: {
+                        Log.d(TAG, "MSG_PROVIDER_PRESENT");
+                        int result = RESULT_UNKNOWN;
+                        try {
+                            AppWidgetProviderInfo info = mAppWidgetHost.getProvider(params);
+                            result = (info != null) ? RESULT_PRESENT : RESULT_NOT_PRESENT;
+                            if (info != null) {
+                                bindAppWidget(info);
+                            }
+                        } catch (InterruptedException e) {
+                            result = RESULT_INTERRUPTED;
+                        }
+                        msg.replyTo.send(Message.obtain(null, MSG_RESULT, result
+                                , 0 /* not used */));
+                        break;
+                    }
+                    case MSG_PROVIDER_UPDATES: {
+                        Log.d(TAG, "MSG_PROVIDER_UPDATES");
+                        int result = RESULT_UNKNOWN;
+                        try {
+                            updateWidgetViaWidgetId();
+                            boolean update = waitForUpdate();
+                            result = update ? RESULT_PRESENT : RESULT_NOT_PRESENT;
+                        } catch (InterruptedException e) {
+                            result = RESULT_INTERRUPTED;
+                        }
+                        msg.replyTo.send(Message.obtain(null, MSG_RESULT, result
+                                , 0 /* not used */));
+                        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.widgetprovider.REGISTER_CALLBACK".equals(intent.getAction())) {
+            mUserHandle = getUserHandleArgument(this, USER_EXTRA, intent);
+            Log.d(TAG, "mUserHandle=" + mUserHandle);
+            setup();
+        }
+        return START_STICKY;
+    }
+
+    private void setup() {
+        HandlerThread handlerThread = new HandlerThread("Widget test callback handler");
+        handlerThread.start();
+        mMessenger = new Messenger(new CheckHandler(handlerThread.getLooper()));
+        mAppWidgetManager = (AppWidgetManager) getSystemService(Context.APPWIDGET_SERVICE);
+        mAppWidgetHost = new SimpleAppWidgetHost(this, 0);
+        mAppWidgetHost.deleteHost();
+        mAppWidgetHost.startListening();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+
+    @Override
+    public void onDestroy() {
+        mAppWidgetHost.stopListening();
+        mAppWidgetHost.deleteAppWidgetId(mAppWidgetId);
+        mAppWidgetHost.deleteHost();
+    }
+
+    private void bindAppWidget(AppWidgetProviderInfo info) {
+        mAppWidgetId = mAppWidgetHost.allocateAppWidgetId();
+        Log.d(TAG, "Registering app widget with id:" + mAppWidgetId);
+        mAppWidgetManager.bindAppWidgetIdIfAllowed(mAppWidgetId, mUserHandle, info.provider, null);
+        mAppWidgetHostView = (SimpleAppWidgetHostView) mAppWidgetHost.createView(this,
+                mAppWidgetId, info);
+        mRemoteViews = new RemoteViews(info.provider.getPackageName(), R.layout.simple_widget);
+    }
+
+    private UserHandle getUserHandleArgument(Context context, String key,
+            Intent intent) {
+        UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
+        int serial = intent.getIntExtra(key, 0);
+        Log.d(TAG, "userId=" + serial);
+        return um.getUserForSerialNumber(serial);
+    }
+
+    private void updateWidgetViaWidgetId() {
+        Log.d(TAG, "Forcing widget update via widget id");
+        mWidgetUpdateSemaphore.drainPermits();
+        // trigger a widget update
+        mAppWidgetManager.updateAppWidget(mAppWidgetId, mRemoteViews);
+    }
+
+    private boolean waitForUpdate() throws InterruptedException {
+        // wait for updateAppWidget to arrive
+        return mWidgetUpdateSemaphore.tryAcquire(20, TimeUnit.SECONDS);
+    }
+
+    private class SimpleAppWidgetHost extends AppWidgetHost {
+        private List<AppWidgetProviderInfo> mProviders;
+        private Semaphore mSemaphore = new Semaphore(0);
+        public SimpleAppWidgetHost(Context context, int hostId) {
+            super(context, hostId);
+            synchronized (this) {
+                mProviders = mAppWidgetManager.getInstalledProvidersForProfile(mUserHandle);
+            }
+        }
+
+        @Override
+        protected void onProvidersChanged() {
+            super.onProvidersChanged();
+            Log.d(TAG, "onProvidersChanged callback received");
+            synchronized (this) {
+                mProviders = mAppWidgetManager.getInstalledProvidersForProfile(mUserHandle);
+            }
+            mSemaphore.release();
+        }
+
+        @Override
+        protected AppWidgetHostView onCreateView(Context context, int id, AppWidgetProviderInfo info) {
+            return new SimpleAppWidgetHostView(context);
+        }
+
+        public AppWidgetProviderInfo getProvider(Bundle params) throws InterruptedException {
+            String packageName = params.getString(PACKAGE_EXTRA);
+            while (mSemaphore.tryAcquire(30, TimeUnit.SECONDS)) {
+                mSemaphore.drainPermits();
+                Log.d(TAG, "checking for " + packageName + " " + mUserHandle);
+                synchronized (this) {
+                    for (AppWidgetProviderInfo providerInfo : mProviders) {
+                        if (providerInfo.provider.getPackageName().equals(packageName)) {
+                            Log.d(TAG, "Provider exists " + packageName
+                                    + " for user " + mUserHandle);
+                            return providerInfo;
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+    private class SimpleAppWidgetHostView extends AppWidgetHostView {
+        public SimpleAppWidgetHostView(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void updateAppWidget(RemoteViews views) {
+            super.updateAppWidget(views);
+            Log.d(TAG, "Host view received widget update");
+            mWidgetUpdateSemaphore.release();
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/src/com/android/cts/widgetprovider/SimpleWidgetProvider.java b/hostsidetests/devicepolicy/app/WidgetProvider/src/com/android/cts/widgetprovider/SimpleWidgetProvider.java
new file mode 100644
index 0000000..3bd4530
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/src/com/android/cts/widgetprovider/SimpleWidgetProvider.java
@@ -0,0 +1,24 @@
+/*
+ * 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.widgetprovider;
+
+import android.appwidget.AppWidgetProvider;
+
+/**
+ * A simple widget provider to test cross-profile widgets.
+ */
+public class SimpleWidgetProvider extends AppWidgetProvider {}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 671c3e5..650e963 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -185,9 +185,6 @@
     protected boolean runDeviceTestsAsUser(
             String pkgName, @Nullable String testClassName, String testMethodName, int userId)
             throws DeviceNotAvailableException {
-        if (testClassName.startsWith(".")) {
-            testClassName = pkgName + testClassName;
-        }
         return runDeviceTests(pkgName, testClassName, testMethodName, userId);
     }
 
@@ -200,6 +197,9 @@
     protected boolean runDeviceTests(String pkgName, @Nullable String testClassName,
             @Nullable String testMethodName, @Nullable Integer userId, @Nullable String params)
                    throws DeviceNotAvailableException {
+        if (testClassName != null && testClassName.startsWith(".")) {
+            testClassName = pkgName + testClassName;
+        }
         TestRunResult runResult = (userId == null && params == null)
                 ? doRunTests(pkgName, testClassName, testMethodName)
                 : doRunTestsAsUser(pkgName, testClassName, testMethodName,
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 93e1aff..acc5b26 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -48,6 +48,9 @@
     private static final String WIFI_CONFIG_CREATOR_PKG = "com.android.cts.wificonfigcreator";
     private static final String WIFI_CONFIG_CREATOR_APK = "CtsWifiConfigCreator.apk";
 
+    private static final String WIDGET_PROVIDER_APK = "CtsWidgetProviderApp.apk";
+    private static final String WIDGET_PROVIDER_PKG = "com.android.cts.widgetprovider";
+
     private static final String ADMIN_RECEIVER_TEST_CLASS =
             MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
 
@@ -596,6 +599,47 @@
                 "testNfcShareEnabled", 0));
     }
 
+    public void testCrossProfileWidgets() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        try {
+            installApp(WIDGET_PROVIDER_APK);
+            getDevice().executeShellCommand("appwidget grantbind --user 0 --package "
+                    + WIDGET_PROVIDER_PKG);
+            startWidgetHostService();
+
+            String commandOutput = changeCrossProfileWidgetForUser(WIDGET_PROVIDER_PKG,
+                    "add-cross-profile-widget", mUserId);
+            assertTrue("Command was expected to succeed " + commandOutput,
+                    commandOutput.contains("Status: ok"));
+
+            assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetTest",
+                    "testCrossProfileWidgetProviderAdded", mUserId));
+            assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetPrimaryUserTest",
+                    "testHasCrossProfileWidgetProvider_true", 0));
+            assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetPrimaryUserTest",
+                    "testHostReceivesWidgetUpdates_true", 0));
+
+            commandOutput = changeCrossProfileWidgetForUser(WIDGET_PROVIDER_PKG,
+                    "remove-cross-profile-widget", mUserId);
+            assertTrue("Command was expected to succeed " + commandOutput,
+                    commandOutput.contains("Status: ok"));
+
+            assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetTest",
+                    "testCrossProfileWidgetProviderRemoved", mUserId));
+            assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetPrimaryUserTest",
+                    "testHasCrossProfileWidgetProvider_false", 0));
+            assertTrue(runDeviceTests(MANAGED_PROFILE_PKG, ".CrossProfileWidgetPrimaryUserTest",
+                    "testHostReceivesWidgetUpdates_false", 0));
+        } finally {
+            changeCrossProfileWidgetForUser(WIDGET_PROVIDER_PKG, "remove-cross-profile-widget",
+                    mUserId);
+            getDevice().uninstallPackage(WIDGET_PROVIDER_PKG);
+        }
+    }
+
     private void disableActivityForUser(String activityName, int userId)
             throws DeviceNotAvailableException {
         String command = "am start -W --user " + userId
@@ -612,7 +656,20 @@
                 + " -c android.intent.category.DEFAULT "
                 + " --es extra-command " + command
                 + " --es extra-restriction-key " + key
-                + " " + MANAGED_PROFILE_PKG + "/.UserRestrictionActivity";
+                + " " + MANAGED_PROFILE_PKG + "/.SetPolicyActivity";
+        String commandOutput = getDevice().executeShellCommand(adbCommand);
+        CLog.logAndDisplay(LogLevel.INFO,
+                "Output for command " + adbCommand + ": " + commandOutput);
+        return commandOutput;
+    }
+
+    private String changeCrossProfileWidgetForUser(String packageName, String command, int userId)
+            throws DeviceNotAvailableException {
+        String adbCommand = "am start -W --user " + userId
+                + " -c android.intent.category.DEFAULT "
+                + " --es extra-command " + command
+                + " --es extra-package-name " + packageName
+                + " " + MANAGED_PROFILE_PKG + "/.SetPolicyActivity";
         String commandOutput = getDevice().executeShellCommand(adbCommand);
         CLog.logAndDisplay(LogLevel.INFO,
                 "Output for command " + adbCommand + ": " + commandOutput);
@@ -627,6 +684,15 @@
                 + getDevice().executeShellCommand(command));
     }
 
+    protected void startWidgetHostService() throws Exception {
+        String command = "am startservice --user 0 "
+                + "-a " + WIDGET_PROVIDER_PKG + ".REGISTER_CALLBACK "
+                + "--ei user-extra " + getUserSerialNumber(mUserId)
+                + " " + WIDGET_PROVIDER_PKG + "/.SimpleAppWidgetHostService";
+        CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": "
+              + getDevice().executeShellCommand(command));
+    }
+
     private void assertAppLinkResult(String methodName) throws DeviceNotAvailableException {
         assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".AppLinkTest", methodName, mUserId));
     }
diff --git a/tests/tests/assist/AndroidManifest.xml b/tests/tests/assist/AndroidManifest.xml
index b6cd684..97bd874 100644
--- a/tests/tests/assist/AndroidManifest.xml
+++ b/tests/tests/assist/AndroidManifest.xml
@@ -29,6 +29,7 @@
               <action android:name="android.intent.action.TEST_START_ACTIVITY_ASSIST_STRUCTURE" />
               <action android:name="android.intent.action.TEST_START_ACTIVITY_DISABLE_CONTEXT" />
               <action android:name="android.intent.action.TEST_START_ACTIVITY_FLAG_SECURE" />
+              <action android:name="android.intent.action.TEST_START_ACTIVITY_LIFECYCLE" />
               <category android:name="android.intent.category.LAUNCHER" />
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>
diff --git a/tests/tests/assist/common/src/android/assist/common/Utils.java b/tests/tests/assist/common/src/android/assist/common/Utils.java
index bf051c0..8d555da 100644
--- a/tests/tests/assist/common/src/android/assist/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -24,8 +24,11 @@
 public class Utils {
     public static final String TESTCASE_TYPE = "testcase_type";
     public static final String TESTINFO = "testinfo";
-    public static final String BROADCAST_INTENT = "android.intent.action.ASSIST_TESTAPP";
-    public static final String BROADCAST_ASSIST_DATA_INTENT = "android.intent.action.ASSIST_DATA";
+    public static final String ACTION_PREFIX = "android.intent.action.";
+    public static final String BROADCAST_INTENT = ACTION_PREFIX + "ASSIST_TESTAPP";
+    public static final String BROADCAST_ASSIST_DATA_INTENT = ACTION_PREFIX + "ASSIST_DATA";
+    public static final String BROADCAST_INTENT_START_ASSIST = ACTION_PREFIX + "START_ASSIST";
+    public static final String ASSIST_RECEIVER_REGISTERED = ACTION_PREFIX + "ASSIST_READY";
     public static final String TEST_ERROR = "Error In Test:";
 
     public static final String ASSIST_STRUCTURE_KEY = "assist_structure";
@@ -33,12 +36,30 @@
     public static final String ASSIST_BUNDLE_KEY = "assist_bundle";
     public static final String ASSIST_SCREENSHOT_KEY = "assist_screenshot";
 
+
+    /** Lifecycle Test intent constants */
+    public static final String LIFECYCLE_PREFIX = ACTION_PREFIX + "lifecycle_";
+    public static final String LIFECYCLE_HASRESUMED = LIFECYCLE_PREFIX + "hasResumed";
+    public static final String LIFECYCLE_ONPAUSE = LIFECYCLE_PREFIX + "onpause";
+    public static final String LIFECYCLE_ONSTOP = LIFECYCLE_PREFIX + "onstop";
+    public static final String LIFECYCLE_ONDESTROY = LIFECYCLE_PREFIX + "ondestroy";
+
+    /** Flag Secure Test intent constants */
+    public static final String FLAG_SECURE_HASRESUMED = ACTION_PREFIX + "flag_secure_hasResumed";
+
+    /** Two second timeout for getting back assist context */
     public static final int TIMEOUT_MS = 2 * 1000; // TODO(awlee): what is the timeout
+    public static final int ACTIVITY_ONRESUME_TIMEOUT_MS = 4000;
+    public static final String EXTRA_REGISTER_RECEIVER = "register_receiver";
 
     /** Test name suffixes */
     public static final String ASSIST_STRUCTURE = "ASSIST_STRUCTURE";
     public static final String DISABLE_CONTEXT = "DISABLE_CONTEXT";
     public static final String FLAG_SECURE = "FLAG_SECURE";
+    public static final String LIFECYCLE = "LIFECYCLE";
+
+    /** Session intent constants */
+    public static final String HIDE_SESSION = "android.intent.action.hide_session";
 
     /**
      * The shim activity that starts the service associated with each test.
@@ -46,10 +67,12 @@
     public static final String getTestActivity(String testCaseType) {
         switch (testCaseType) {
             case ASSIST_STRUCTURE:
-            case FLAG_SECURE:
                 return "service.AssistStructureActivity";
             case DISABLE_CONTEXT:
                 return "service.DisableContextActivity";
+            case FLAG_SECURE:
+            case LIFECYCLE:
+                return "service.DelayedAssistantActivity";
             default:
                 return "";
         }
@@ -67,6 +90,9 @@
             case FLAG_SECURE:
                 return new ComponentName(
                         "android.assist.testapp", "android.assist.testapp.SecureActivity");
+            case LIFECYCLE:
+                return new ComponentName(
+                        "android.assist.testapp", "android.assist.testapp.LifecycleActivity");
             default:
                 return new ComponentName("","");
         }
diff --git a/tests/tests/assist/service/AndroidManifest.xml b/tests/tests/assist/service/AndroidManifest.xml
index 2c5206a..cdbeef0 100644
--- a/tests/tests/assist/service/AndroidManifest.xml
+++ b/tests/tests/assist/service/AndroidManifest.xml
@@ -34,7 +34,6 @@
       <activity android:name=".AssistStructureActivity" >
           <intent-filter>
               <action android:name="android.intent.action.START_TEST_ASSIST_STRUCTURE" />
-              <action android:name="android.intent.action.START_TEST_FLAG_SECURE" />
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>
       </activity>
@@ -45,6 +44,14 @@
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>
       </activity>
+      <activity android:name=".DelayedAssistantActivity"
+                android:label="Delay Assistant Start Activity">
+          <intent-filter>
+              <action android:name="android.intent.action.START_TEST_LIFECYCLE" />
+              <action android:name="android.intent.action.START_TEST_FLAG_SECURE" />
+              <category android:name="android.intent.category.DEFAULT" />
+          </intent-filter>
+      </activity>
       <service android:name=".MainInteractionSessionService"
               android:permission="android.permission.BIND_VOICE_INTERACTION"
               android:process=":session">
diff --git a/tests/tests/assist/service/res/layout/assist_layer.xml b/tests/tests/assist/service/res/layout/assist_layer.xml
new file mode 100644
index 0000000..49f35c9
--- /dev/null
+++ b/tests/tests/assist/service/res/layout/assist_layer.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/assist_layer"
+        android:layout_width="match_parent"
+        android:background="@color/assist_layer_background"
+        android:layout_height="match_parent">
+    <TextView
+        android:layout_centerInParent="true"
+        android:text="@string/test_assistant_text"
+        android:textColor="@android:color/white"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+</RelativeLayout>
diff --git a/tests/tests/assist/service/res/values/colors.xml b/tests/tests/assist/service/res/values/colors.xml
new file mode 100644
index 0000000..4423140
--- /dev/null
+++ b/tests/tests/assist/service/res/values/colors.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="assist_layer_background">#aa000000</color>
+</resources>
diff --git a/tests/tests/assist/service/res/values/strings.xml b/tests/tests/assist/service/res/values/strings.xml
new file mode 100644
index 0000000..ea959e6
--- /dev/null
+++ b/tests/tests/assist/service/res/values/strings.xml
@@ -0,0 +1,18 @@
+<!--
+  Copyright 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. -->
+
+<resources>
+    <string name="test_assistant_text">I am an Assistant</string>
+</resources>
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java b/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.java
new file mode 100644
index 0000000..31d1694
--- /dev/null
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/DelayedAssistantActivity.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 android.assist.service;
+
+import android.app.Activity;
+import android.assist.common.Utils;
+import android.content.Intent;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.util.Log;
+
+public class DelayedAssistantActivity extends Activity {
+    static final String TAG = "DelatyedAssistantActivity";
+
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(this, MainInteractionService.class));
+        intent.putExtra(Utils.EXTRA_REGISTER_RECEIVER, true);
+        finish();
+        ComponentName serviceName = startService(intent);
+        Log.i(TAG, "Started service: " + serviceName);
+    }
+}
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
index 85bd6ea..7530933 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
@@ -16,8 +16,15 @@
 
 package android.assist.service;
 
+import static android.service.voice.VoiceInteractionSession.SHOW_WITH_ASSIST;
+import static android.service.voice.VoiceInteractionSession.SHOW_WITH_SCREENSHOT;
+
+import android.assist.common.Utils;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionSession;
@@ -27,6 +34,7 @@
     static final String TAG = "MainInteractionService";
     private Intent mIntent;
     private boolean mReady = false;
+    private BroadcastReceiver mBroadcastReceiver;
 
     @Override
     public void onReady() {
@@ -36,7 +44,7 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        Log.i(TAG, "onStartCommand received");
+        Log.i(TAG, "onStartCommand received - intent: " + intent);
         mIntent = intent;
         maybeStart();
         return START_NOT_STICKY;
@@ -47,14 +55,40 @@
             Log.wtf(TAG, "Can't start session because either intent is null or onReady() "
                     + "has not been called yet. mIntent = " + mIntent + ", mReady = " + mReady);
         } else {
-            Log.i(TAG, "Yay! about to start session");
             if (isActiveService(this, new ComponentName(this, getClass()))) {
-                showSession(new Bundle(), VoiceInteractionSession.SHOW_WITH_ASSIST |
-                        VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
+                if (mIntent.getBooleanExtra(Utils.EXTRA_REGISTER_RECEIVER, false)) {
+                    Log.i(TAG, "Registering receiver to start session later");
+                    if (mBroadcastReceiver == null) {
+                        mBroadcastReceiver = new MainInteractionServiceBroadcastReceiver();
+                        registerReceiver(mBroadcastReceiver, 
+                                new IntentFilter(Utils.BROADCAST_INTENT_START_ASSIST));
+                    }
+                    sendBroadcast(new Intent(Utils.ASSIST_RECEIVER_REGISTERED));
+                } else {
+                    Log.i(TAG, "Yay! about to start session");
+                    showSession(new Bundle(), VoiceInteractionSession.SHOW_WITH_ASSIST |
+                                VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
+                }
             } else {
                 Log.wtf(TAG, "**** Not starting MainInteractionService because" +
                     " it is not set as the current voice interaction service");
             }
         }
     }
+
+    private class MainInteractionServiceBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(Utils.BROADCAST_INTENT_START_ASSIST)) {
+                showSession(new Bundle(), SHOW_WITH_ASSIST | SHOW_WITH_SCREENSHOT);
+            }
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mBroadcastReceiver != null) {
+            unregisterReceiver(mBroadcastReceiver);
+        }
+    }
 }
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
index 9a835c2..f297b3e 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
@@ -18,13 +18,17 @@
 
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
+import android.assist.service.R;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionSession;
 import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
 
 import java.io.ByteArrayOutputStream;
 
@@ -39,6 +43,7 @@
 
     private boolean hasReceivedAssistData = false;
     private boolean hasReceivedScreenshot = false;
+    private BroadcastReceiver mReceiver;
 
     MainInteractionSession(Context context) {
         super(context);
@@ -48,12 +53,27 @@
     @Override
     public void onCreate() {
         super.onCreate();
+        mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (action.equals(Utils.HIDE_SESSION)) {
+                    hide();
+                }
+            }
+        };
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.HIDE_SESSION);
+        mContext.registerReceiver(mReceiver, filter);
     }
 
     @Override
     public void onDestroy() {
         Log.i(TAG, "onDestroy()");
         super.onDestroy();
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
     }
 
     @Override
@@ -115,6 +135,15 @@
         }
     }
 
+    @Override
+    public View onCreateContentView() {
+        LayoutInflater f = getLayoutInflater();
+        if (f == null) {
+            Log.wtf(TAG, "layout inflater was null");
+        }
+        return f.inflate(R.layout.assist_layer,null);
+    }
+
     class DoneReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index bdf3d4a..a7e7087 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -48,7 +48,7 @@
     protected BroadcastReceiver mReceiver;
     protected Bundle mAssistBundle;
     protected Context mContext;
-    protected CountDownLatch mLatch;
+    protected CountDownLatch mLatch, mAssistantReadyLatch;
     private String mTestName;
 
     public AssistTestBase() {
@@ -58,6 +58,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        mAssistantReadyLatch = new CountDownLatch(1);
         mContext = getInstrumentation().getTargetContext();
         SystemUtil.runShellCommand(getInstrumentation(),
             "settings put secure assist_structure_enabled 1");
@@ -71,6 +72,7 @@
         mContext.unregisterReceiver(mReceiver);
         mTestActivity.finish();
         super.tearDown();
+        mContext.sendBroadcast(new Intent(Utils.HIDE_SESSION));
     }
 
     protected void startTestActivity(String testName) {
@@ -84,9 +86,32 @@
     }
 
     /**
+     * Called when waiting for Assistant's Broadcast Receiver to be setup
+     */
+    public void waitForAssistantToBeReady() throws Exception {
+        Log.i(TAG, "waiting for assistant to be ready before continuing");
+        if (!mAssistantReadyLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Assistant was not ready before timeout of: " + Utils.TIMEOUT_MS + "msec");
+        }
+    }
+
+    /**
+     * Send broadcast to MainInteractionService to start a session
+     */
+    protected void startSession() {
+        mContext.sendBroadcast(new Intent(Utils.BROADCAST_INTENT_START_ASSIST));
+    }
+
+    /**
      * Called after startTestActivity
      */
     protected boolean waitForBroadcast() throws Exception {
+        mTestActivity.start3pApp(mTestName);
+        mTestActivity.startTest(mTestName);
+        return waitForContext();
+    }
+
+    protected boolean waitForContext() throws Exception {
         mLatch = new CountDownLatch(1);
         if (mReceiver != null) {
             mContext.unregisterReceiver(mReceiver);
@@ -95,8 +120,6 @@
         mContext.registerReceiver(mReceiver,
             new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
 
-        mTestActivity.start3pApp(mTestName);
-        mTestActivity.startTest(mTestName);
         if (!mLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
             fail("Failed to receive broadcast in " + Utils.TIMEOUT_MS + "msec");
             return false;
@@ -188,4 +211,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
index 04bea77..9b29407 100644
--- a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
+++ b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
@@ -97,4 +97,4 @@
 
         verifyAssistDataNullness(true, true, true, true);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
index fc14900..40bf7a7 100644
--- a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
@@ -17,8 +17,14 @@
 package android.assist.cts;
 
 import android.assist.common.Utils;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Test we receive proper assist data (root assistStructure with no children) when the assistant is
@@ -26,10 +32,13 @@
  */
 public class FlagSecureTest extends AssistTestBase {
 
-    static final String TAG = "DisableContextTest";
+    static final String TAG = "FlagSecureTest";
 
     private static final String TEST_CASE_TYPE = Utils.FLAG_SECURE;
 
+    private BroadcastReceiver mReceiver;
+    private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+
     public FlagSecureTest() {
         super();
     }
@@ -37,13 +46,35 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
+        setUpAndRegisterReceiver();
         startTestActivity(TEST_CASE_TYPE);
-        waitForBroadcast();
     }
 
     @Override
     public void tearDown() throws Exception {
         super.tearDown();
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+            mReceiver = null;
+        }
+    }
+
+    private void setUpAndRegisterReceiver() {
+        if (mReceiver != null) {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mReceiver = new FlagSecureTestBroadcastReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Utils.FLAG_SECURE_HASRESUMED);
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    private void waitForOnResume() throws Exception {
+        Log.i(TAG, "waiting for onResume() before continuing");
+        if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+        }
     }
 
     public void testSecureActivity() throws Exception {
@@ -52,4 +83,16 @@
         // verify that we have only the root window and not its children.
         verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), true);
     }
-}
\ No newline at end of file
+
+    private class FlagSecureTestBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Utils.FLAG_SECURE_HASRESUMED)) {
+                mHasResumedLatch.countDown();
+            } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+                mAssistantReadyLatch.countDown();
+            }
+        }
+    }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
new file mode 100644
index 0000000..19a1be5
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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 android.assist.cts;
+
+import android.assist.TestStartActivity;
+import android.assist.common.Utils;
+
+import android.app.Activity;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.cts.util.SystemUtil;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.lang.Override;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/** Test we receive proper assist data when context is disabled or enabled */
+
+public class LifecycleTest extends AssistTestBase {
+    private static final String TAG = "LifecycleTest";
+    private static final String action_hasResumed = Utils.LIFECYCLE_HASRESUMED;
+    private static final String action_onPause = Utils.LIFECYCLE_ONPAUSE;
+    private static final String action_onStop = Utils.LIFECYCLE_ONSTOP;
+    private static final String action_onDestroy = Utils.LIFECYCLE_ONDESTROY;
+
+    private BroadcastReceiver mLifecycleTestBroadcastReceiver;
+    private CountDownLatch mHasResumedLatch = new CountDownLatch(1);
+    private CountDownLatch mActivityLifecycleLatch = new CountDownLatch(1);
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        setUpAndRegisterReceiver();
+        startTestActivity(Utils.LIFECYCLE);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (mLifecycleTestBroadcastReceiver != null) {
+            mContext.unregisterReceiver(mLifecycleTestBroadcastReceiver);
+            mLifecycleTestBroadcastReceiver = null;
+        }
+    }
+
+    private void setUpAndRegisterReceiver() {
+        if (mLifecycleTestBroadcastReceiver != null) {
+            mContext.unregisterReceiver(mLifecycleTestBroadcastReceiver);
+        }
+        mLifecycleTestBroadcastReceiver = new LifecycleTestReceiver();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(action_hasResumed);
+        filter.addAction(action_onPause);
+        filter.addAction(action_onStop);
+        filter.addAction(action_onDestroy);
+        filter.addAction(Utils.ASSIST_RECEIVER_REGISTERED);
+        mContext.registerReceiver(mLifecycleTestBroadcastReceiver, filter);
+
+    }
+
+    private void waitForOnResume() throws Exception {
+        Log.i(TAG, "waiting for onResume() before continuing");
+        if (!mHasResumedLatch.await(Utils.ACTIVITY_ONRESUME_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Activity failed to resume in " + Utils.ACTIVITY_ONRESUME_TIMEOUT_MS + "msec");
+        }
+    }
+
+    private void waitAndSeeIfLifecycleMethodsAreTriggered() throws Exception {
+        if (mActivityLifecycleLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("One or more lifecycle methods were called after triggering assist");
+        }
+    }
+
+    public void testLayerDoesNotTriggerLifecycleMethods() throws Exception {
+        mTestActivity.startTest(Utils.LIFECYCLE);
+        waitForAssistantToBeReady();
+        mTestActivity.start3pApp(Utils.LIFECYCLE);
+        waitForOnResume();
+        startSession();
+        waitForContext();
+        waitAndSeeIfLifecycleMethodsAreTriggered();
+    }
+
+    private class LifecycleTestReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(action_hasResumed)) {
+                mHasResumedLatch.countDown();
+            } else if (action.equals(action_onPause)) {
+                mActivityLifecycleLatch.countDown();
+            } else if (action.equals(action_onStop)) {
+                mActivityLifecycleLatch.countDown();
+            } else if (action.equals(action_onDestroy)) {
+                mActivityLifecycleLatch.countDown();
+            } else if (action.equals(Utils.ASSIST_RECEIVER_REGISTERED)) {
+                mAssistantReadyLatch.countDown();
+            }
+        }
+    }
+}
diff --git a/tests/tests/assist/testapp/AndroidManifest.xml b/tests/tests/assist/testapp/AndroidManifest.xml
index 371ae7b..8d6169c 100644
--- a/tests/tests/assist/testapp/AndroidManifest.xml
+++ b/tests/tests/assist/testapp/AndroidManifest.xml
@@ -39,5 +39,13 @@
                 <category android:name="android.intent.category.VOICE" />
             </intent-filter>
         </activity>
+        <activity android:name="LifecycleActivity"
+                  android:label="Life Cycle Check Activity"
+                  android:theme="@android:style/Theme.Material.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.TEST_APP_LIFECYCLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java
new file mode 100644
index 0000000..4e1dc80
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/LifecycleActivity.java
@@ -0,0 +1,60 @@
+/*
+ * 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 android.assist.testapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class LifecycleActivity extends Activity {
+    private static final String TAG = "LifecycleActivity";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, "LifecycleActivity created");
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        Log.i(TAG, "Activity has resumed");
+        sendBroadcast(new Intent("android.intent.action.lifecycle_hasResumed"));
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        Log.i(TAG, "activity was paused");
+        sendBroadcast(new Intent("android.intent.action.lifecycle_onpause"));
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        Log.i(TAG, "activity was stopped");
+        sendBroadcast(new Intent("android.intent.action.lifecycle_onstop"));
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        Log.i(TAG, "activity was destroyed");
+        sendBroadcast(new Intent("android.intent.action.lifecycle_ondestroy"));
+    }
+}
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/SecureActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/SecureActivity.java
index 83f7549..d9b2ff2 100644
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/SecureActivity.java
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/SecureActivity.java
@@ -17,6 +17,7 @@
 package android.assist.testapp;
 
 import android.app.Activity;
+import android.content.Intent;
 import android.os.Bundle;
 import android.util.Log;
 
@@ -24,7 +25,6 @@
 
 public class SecureActivity extends Activity {
     static final String TAG = "SecureActivity";
-
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -33,4 +33,11 @@
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
             WindowManager.LayoutParams.FLAG_SECURE);
     }
-}
\ No newline at end of file
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        Log.i(TAG, "Activity has resumed");     
+        sendBroadcast(new Intent("android.intent.action.flag_secure_hasResumed"));
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java b/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
index 1881774..8a217fd 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
@@ -32,6 +32,7 @@
     private SurfaceView mSurfaceView;
     private int currentWidth = 0;
     private int currentHeight = 0;
+    private final Object sizeLock = new Object();
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -55,6 +56,12 @@
                             timeOutMs, expectWidth, expectHeight));
         }
 
+        synchronized(sizeLock) {
+            if (expectWidth == currentWidth && expectHeight == currentHeight) {
+                return true;
+            }
+        }
+
         int waitTimeMs = timeOutMs;
         boolean changeSucceeded = false;
         while (!changeSucceeded && waitTimeMs > 0) {
@@ -87,8 +94,10 @@
     @Override
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
         Log.i(TAG, "Surface Changed to: " + width + "x" + height);
-        currentWidth = width;
-        currentHeight = height;
+        synchronized (sizeLock) {
+            currentWidth = width;
+            currentHeight = height;
+        }
         surfaceChangedDone.open();
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index 7330a4c..c136b67 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -619,8 +619,8 @@
                 mPreviewSize.getHeight());
         assertTrue("wait for surface change to " + mPreviewSize.toString() + " timed out", res);
         mPreviewSurface = holder.getSurface();
-        assertTrue("Preview surface is invalid", mPreviewSurface.isValid());
         assertNotNull("Preview surface is null", mPreviewSurface);
+        assertTrue("Preview surface is invalid", mPreviewSurface.isValid());
     }
 
     /**
diff --git a/tests/tests/os/src/android/os/cts/StatFsTest.java b/tests/tests/os/src/android/os/cts/StatFsTest.java
index 67afde9..a0653fd 100644
--- a/tests/tests/os/src/android/os/cts/StatFsTest.java
+++ b/tests/tests/os/src/android/os/cts/StatFsTest.java
@@ -46,15 +46,15 @@
         assertTrue(stat.getBlockSize() > 0);
         assertTrue(stat.getBlockCount() > 0);
         assertTrue(stat.getFreeBlocks() >= stat.getAvailableBlocks());
-        assertTrue(stat.getAvailableBlocks() > 0);
+        assertTrue(stat.getAvailableBlocks() >= 0);
 
         assertTrue(stat.getBlockSizeLong() > 0);
         assertTrue(stat.getBlockCountLong() > 0);
         assertTrue(stat.getFreeBlocksLong() >= stat.getAvailableBlocksLong());
-        assertTrue(stat.getAvailableBlocksLong() > 0);
+        assertTrue(stat.getAvailableBlocksLong() >= 0);
 
-        assertTrue(stat.getFreeBytes() > 0);
-        assertTrue(stat.getAvailableBytes() > 0);
+        assertTrue(stat.getFreeBytes() >= 0);
+        assertTrue(stat.getAvailableBytes() >= 0);
         assertTrue(stat.getTotalBytes() > 0);
     }
 }