Merge "Camera: reduce number of buffers allocated in PerformanceTest" into mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 41f9dc3..975ac47 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -194,6 +194,7 @@
     CtsSecurityTestCases \
     CtsSignatureTestCases \
     CtsSpeechTestCases \
+    CtsSystemUiTestCases \
     CtsTelecomTestCases \
     CtsTelecomTestCases2 \
     CtsTelephonyTestCases \
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index d0d5ff0..85e5b734 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1398,6 +1398,13 @@
             </intent-filter>
         </activity-alias>
 
+        <activity android:name=".managedprovisioning.AuthenticationBoundKeyTestActivity">
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.AUTH_BOUND_KEY_TEST" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".managedprovisioning.ByodFlowTestActivity"
                 android:launchMode="singleTask"
                 android:label="@string/provisioning_byod">
@@ -1425,6 +1432,8 @@
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_KEYGUARD_DISABLED_FEATURES" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_LOCKNOW" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.TEST_NFC_BEAM" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.TEST_CROSS_PROFILE_INTENTS_DIALOG" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.TEST_APP_LINKING_DIALOG" />
                 <category android:name="android.intent.category.DEFAULT"></category>
             </intent-filter>
         </activity>
@@ -1452,12 +1461,19 @@
 
         <activity android:name=".managedprovisioning.CrossProfileTestActivity">
             <intent-filter>
-                <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE" />
                 <!-- We need to have at least one activity listening to this intent in the parent
                      to test if it is forwarded from the managed profile to the parent -->
                 <action android:name="android.provider.MediaStore.RECORD_SOUND" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_PERSONAL" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_WORK" />
                 <category android:name="android.intent.category.DEFAULT"></category>
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <category android:name="android.intent.category.DEFAULT"></category>
+                <data android:scheme="http" android:host="com.android.cts.verifier" />
+            </intent-filter>
         </activity>
 
         <activity android:name=".managedprovisioning.WorkStatusTestActivity">
@@ -1574,6 +1590,18 @@
                     android:value="android.software.live_tv" />
         </activity>
 
+        <activity android:name=".tv.AppLinkTestActivity"
+            android:label="@string/tv_app_link_test"
+            android:launchMode="singleTask">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_tv" />
+            <meta-data android:name="test_required_features"
+                android:value="android.software.live_tv" />
+        </activity>
+
         <activity android:name=".screenpinning.ScreenPinningTestActivity"
             android:label="@string/screen_pinning_test">
             <intent-filter>
diff --git a/apps/CtsVerifier/jni/verifier/Android.mk b/apps/CtsVerifier/jni/verifier/Android.mk
index 6bdf71c..4840e62 100644
--- a/apps/CtsVerifier/jni/verifier/Android.mk
+++ b/apps/CtsVerifier/jni/verifier/Android.mk
@@ -30,6 +30,6 @@
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
 
-LOCAL_LDLIBS := -llog
+LOCAL_SHARED_LIBRARIES := liblog
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/apps/CtsVerifier/res/drawable/app_link_img.png b/apps/CtsVerifier/res/drawable/app_link_img.png
new file mode 100644
index 0000000..851fc6f
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable/app_link_img.png
Binary files differ
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 77566a3..68f9d82 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1278,6 +1278,23 @@
     <string name="provisioning_byod_no_audio_capture_resolver">No audio capture app present. Skip test.</string>
     <string name="provisioning_byod_capture_media_error">Error while capturing media from managed profile.</string>
 
+    <string name="provisioning_byod_auth_bound_key">Autentication-boud keys</string>
+    <string name="provisioning_byod_auth_bound_key_info">
+        This test verifies keystore cryptographic keys can be bound to device credentials.
+        These keys should only be available if there was a recent enough authentication.
+    </string>
+    <string name="provisioning_byod_auth_bound_key_instruction">
+        This test verifies keystore cryptographic keys can be bound to device lockscreen challenge or fingerprints (if available).
+        These keys should only be available if there was a recent enough authentication. \n
+
+        1. Press "Set up" to open Security settings. Create a lockscreen password and if available, enroll a fingerprint.\n
+        2. Go through the list of tests.\n
+        3. Mark the overall test pass or fail.\n
+        4. Once the set of tests are completed, remove the lockscreen challenge.
+    </string>
+    <string name="provisioning_byod_auth_bound_key_set_up">Set up</string>
+    <string name="provisioning_byod_lockscreen_bound_key">Lockscreen-bound key test</string>
+    <string name="provisioning_byod_fingerprint_bound_key">Fingerprint-bound key test</string>
     <!-- Strings for DeskClock -->
     <string name="deskclock_tests">Alarms and Timers Tests</string>
     <string name="deskclock_tests_info">
@@ -1436,12 +1453,13 @@
     <string name="provisioning_byod_profile_visible">Profile-aware accounts settings</string>
     <string name="provisioning_byod_admin_visible">Profile-aware device administrator settings</string>
     <string name="provisioning_byod_workapps_visible">Badged work apps visible in Launcher</string>
-    <string name="provisioning_byod_cross_profile">Open app cross profiles</string>
-    <string name="provisioning_byod_cross_profile_app_personal">
-        You selected the CTS Verifier option.
-    </string>
+    <string name="provisioning_byod_cross_profile_from_personal">Open app cross profiles from the personal side</string>
+    <string name="provisioning_byod_cross_profile_from_work">Open app cross profiles from the work side</string>
+    <string name="provisioning_app_linking">App links from the work side</string>
+    <string name="provisioning_byod_cross_profile_app_personal">You selected the personal option.</string>
     <string name="provisioning_byod_cross_profile_app_work">You selected the Work option.</string>
-    <string name="provisioning_byod_cross_profile_instruction">
+    <string name="provisioning_byod_cross_profile_app_ctsverifier"> You selected the ctsverifier option </string>
+    <string name="provisioning_byod_cross_profile_from_personal_instruction">
         Please press the Go button to start an action.\n
         \n
         You should be asked to choose either \"CTS Verifier\" or \"Work\" to complete the action.
@@ -1449,6 +1467,25 @@
         \n
         Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
     </string>
+    <string name="provisioning_byod_cross_profile_from_work_instruction">
+        Please press the Go button to start an action.\n
+        \n
+        You should be asked to choose either \"CTS Verifier\" or \"Personal\" to complete the action.
+        Pressing either should bring up a page stating your choice.\n
+        \n
+        Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
+    </string>
+    <string name="provisioning_byod_app_linking_instruction">
+        Please press the Go button to start an action.\n
+        \n
+        You should be asked to choose either \"CTS Verifier\" or \"Personal\" to complete the action.\n
+        - If you choose \"CTS Verifier\", you should see a page stating your chose \"CTS Verifier\".\n
+        - If you choose \"Personal\", you should be presented with another dialog between \"CTS Verifier\"
+        and some other apps. In this case, you should choose \"CTS verifier\".\n
+        You should then see a page stating you chose \"Personal\".\n
+        \n
+        Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
+    </string>
     <string name="provisioning_byod_keyguard_disabled_features">Keyguard disabled features</string>
     <string name="provisioning_byod_keyguard_disabled_features_info">
         This test exercises Keyguard Disabled Features. Follow instructions above.
@@ -1640,6 +1677,7 @@
     <string name="provisioning_byod_send_share_intent">Send share intent</string>
     <string name="provisioning_byod_cannot_resolve_beam_activity">Cannot find beam activity</string>
 
+    <string name="test_failed_cannot_start_intent">Cannot start the given intent.</string>
     <string name="provisioning_byod_no_activity">Cannot communicate with activity in the work profile.</string>
     <string name="provisioning_byod_delete_profile">Initiate deletion of work profile.</string>
     <string name="provisioning_byod_profile_deleted">Work profile deleted.</string>
@@ -1875,7 +1913,6 @@
     Do you see the programs named \"Dummy Program\" and their descriptions
     "Dummy Program Description" in the EPG?
     </string>
-    <string name="tv_input_discover_test_yes">Yes</string>
 
     <string name="tv_parental_control_test">TV app parental controls test</string>
     <string name="tv_parental_control_test_info">
@@ -1964,6 +2001,24 @@
     The playback position should be moved to the next position.
     </string>
 
+    <string name="tv_app_link_test">TV app app-link test</string>
+    <string name="tv_app_link_test_info">
+    Verify that the bundled TV app supports linking to channel apps. If TV input service provides
+    links for its specific channels, TV app should show the links in a proper format.
+    </string>
+    <string name="tv_app_link_test_select_app_link">
+    Select the \"Launch TV app\" button, then check if you can see a menu with \"Cts App-Link Text\"
+    text in red background. If you see the link, select it to follow the link.
+    </string>
+    <string name="tv_app_link_test_verify_link_clicked">
+    The app-link must have been clicked and the activity should be changed correctly.
+    </string>
+    <string name="tv_input_link_test_verify_link_interface">
+    Do you see the app-link card similar to the image on the left?\n
+    1) You should see the poster art image, but the color could be differ.\n
+    2) You should see the text \"Cts App-Link Text\".\n
+    </string>
+
     <string name="overlay_view_text">Overlay View Dummy Text</string>
     <string name="fake_rating">Fake</string>
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
index 789effa..91b8d93 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.database.DataSetObserver;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -41,6 +42,7 @@
  * Instructions are shown on top of the screen and a test preparation button is provided.
  */
 public abstract class DialogTestListActivity extends PassFailButtons.TestListActivity {
+    private final String TAG = "DialogTestListActivity";
     private final int mLayoutId;
     private final int mTitleStringId;
     private final int mInfoStringId;
@@ -170,7 +172,13 @@
             mCurrentTestPosition = position;
             ((DialogTestListItem)test).performTest(this);
         } else {
-            super.handleItemClick(l, v, position, id);
+            try {
+                super.handleItemClick(l, v, position, id);
+            } catch (ActivityNotFoundException e) {
+                Log.d(TAG, "handleItemClick() threw exception: ", e);
+                setTestResult(test, TestResult.TEST_RESULT_FAILED);
+                showToast(R.string.test_failed_cannot_start_intent);
+            }
         }
     }
 
@@ -196,7 +204,7 @@
         // do nothing, override in subclass if needed
     }
 
-    protected void setTestResult(DialogTestListItem test, int result) {
+    protected void setTestResult(TestListAdapter.TestListItem test, int result) {
         // Bundle result in an intent to feed into handleLaunchTestResult
         Intent resultIntent = new Intent();
         TestResult.addResultData(resultIntent, result, test.testName, /* testDetails */ null,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index 51e0a62..3c108da 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -232,6 +232,7 @@
 
     public static final Feature[] ALL_MNC_FEATURES = {
             new Feature(PackageManager.FEATURE_MIDI, false),
+            new Feature(PackageManager.FEATURE_AUDIO_PRO, false),
     };
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AuthenticationBoundKeyTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AuthenticationBoundKeyTestActivity.java
new file mode 100644
index 0000000..073412d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/AuthenticationBoundKeyTestActivity.java
@@ -0,0 +1,381 @@
+package com.android.cts.verifier.managedprovisioning;
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.KeyguardManager;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.CountDownTimer;
+import android.provider.Settings;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.UserNotAuthenticatedException;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Toast;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.DialogTestListActivity;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestResult;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+/**
+ * Test device credential-bound keys in work profile.
+ * Currently there are two types, one is keys bound to lockscreen passwords which can be configured
+ * to remain available within a certain timeout after the latest successful user authentication.
+ * The other is keys bound to fingerprint authentication which require explicit fingerprint
+ * authentication before they can be accessed.
+ */
+public class AuthenticationBoundKeyTestActivity extends DialogTestListActivity {
+
+    public static final String ACTION_AUTH_BOUND_KEY_TEST =
+            "com.android.cts.verifier.managedprovisioning.action.AUTH_BOUND_KEY_TEST";
+
+    private static final int AUTHENTICATION_DURATION_SECONDS = 5;
+    private static final String LOCKSCREEN_KEY_NAME = "mp_lockscreen_key";
+    private static final String FINGERPRINT_KEY_NAME = "mp_fingerprint_key";
+    private static final byte[] SECRET_BYTE_ARRAY = new byte[] {1, 2, 3, 4, 5, 6};
+    private static final int CONFIRM_CREDENTIALS_REQUEST_CODE = 1;
+    private static final int FINGERPRINT_PERMISSION_REQUEST_CODE = 0;
+
+    private static final int LOCKSCREEN = 1;
+    private static final int FINGERPRINT = 2;
+
+    private static final String KEYSTORE_NAME = "AndroidKeyStore";
+    private static final String CIPHER_TRANSFORMATION =  KeyProperties.KEY_ALGORITHM_AES + "/"
+            + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7;
+
+
+    private KeyguardManager mKeyguardManager;
+    private FingerprintManager mFingerprintManager;
+    private boolean mFingerprintSupported;
+
+    private DialogTestListItem mLockScreenBoundKeyTest;
+    private DialogTestListItem mFingerprintBoundKeyTest;
+
+    private Cipher mFingerprintCipher;
+
+    public AuthenticationBoundKeyTestActivity() {
+        super(R.layout.provisioning_byod,
+                R.string.provisioning_byod_auth_bound_key,
+                R.string.provisioning_byod_auth_bound_key_info,
+                R.string.provisioning_byod_auth_bound_key_instruction);
+    }
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
+        mFingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
+        mFingerprintSupported = mFingerprintManager != null
+                && mFingerprintManager.isHardwareDetected();
+        // Need to have valid mFingerprintSupported value before calling super.onCreate() because
+        // mFingerprintSupported is used in setupTests() which gets called by super.onCreate().
+        super.onCreate(savedInstanceState);
+
+        mPrepareTestButton.setText(R.string.provisioning_byod_auth_bound_key_set_up);
+        mPrepareTestButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View arg0) {
+                startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
+            }
+        });
+        if (mFingerprintSupported) {
+            requestPermissions(new String[] {Manifest.permission.USE_FINGERPRINT},
+                    FINGERPRINT_PERMISSION_REQUEST_CODE);
+        }
+    }
+
+    private class LockscreenCountDownTester extends CountDownTimer {
+
+        private Toast mToast;
+
+        public LockscreenCountDownTester() {
+            // Wait for AUTHENTICATION_DURATION_SECONDS so the key is evicted before the real test.
+            super(AUTHENTICATION_DURATION_SECONDS * 1000, 1000);
+            mToast = Toast.makeText(AuthenticationBoundKeyTestActivity.this, "", Toast.LENGTH_SHORT);
+        }
+
+        @Override
+        public void onFinish() {
+            mToast.cancel();
+            if (tryEncryptWithLockscreenKey()) {
+                showToast("Test failed. Key accessible without auth.");
+                setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+            } else {
+                // Start the Confirm Credentials screen.
+                Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null);
+                if (intent != null) {
+                    startActivityForResult(intent, CONFIRM_CREDENTIALS_REQUEST_CODE);
+                } else {
+                    showToast("Test failed. No lockscreen password exists.");
+                    setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                }
+            }
+        }
+
+        @Override
+        public void onTick(long millisUntilFinished) {
+            mToast.setText(String.format("Lockscreen challenge start in %d seconds..",
+                    millisUntilFinished / 1000));
+            mToast.show();
+        }
+    }
+
+
+    @Override
+    protected void setupTests(ArrayTestListAdapter adapter) {
+        mLockScreenBoundKeyTest = new DialogTestListItem(this,
+                R.string.provisioning_byod_lockscreen_bound_key,
+                "BYOD_LockScreenBoundKeyTest") {
+
+            @Override
+            public void performTest(DialogTestListActivity activity) {
+                if (checkPreconditions()) {
+                    createKey(LOCKSCREEN);
+                    new LockscreenCountDownTester().start();
+                }
+            }
+        };
+        adapter.add(mLockScreenBoundKeyTest);
+
+        if (mFingerprintSupported) {
+            mFingerprintBoundKeyTest = new DialogTestListItem(this,
+                    R.string.provisioning_byod_fingerprint_bound_key,
+                    "BYOD_FingerprintBoundKeyTest") {
+
+                @Override
+                public void performTest(DialogTestListActivity activity) {
+                    if (checkPreconditions()) {
+                        createKey(FINGERPRINT);
+                        mFingerprintCipher = initFingerprintEncryptionCipher();
+                        if (tryEncryptWithFingerprintKey(mFingerprintCipher)) {
+                            showToast("Test failed. Key accessible without auth.");
+                            setTestResult(mFingerprintBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                        } else {
+                            new FingerprintAuthDialogFragment().show(getFragmentManager(),
+                                    "fingerprint_dialog");
+                        }
+                    }
+                }
+            };
+            adapter.add(mFingerprintBoundKeyTest);
+        }
+    }
+
+    private boolean checkPreconditions() {
+        if (!mKeyguardManager.isKeyguardSecure()) {
+            showToast("Please set a lockscreen password.");
+            return false;
+        } else if (mFingerprintSupported && !mFingerprintManager.hasEnrolledFingerprints()) {
+            showToast("Please enroll a fingerprint.");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    private String getKeyName(int testType) {
+        return testType == LOCKSCREEN ? LOCKSCREEN_KEY_NAME : FINGERPRINT_KEY_NAME;
+    }
+    /**
+     * Creates a symmetric key in the Android Key Store which can only be used after the user has
+     * authenticated with device credentials.
+     */
+    private void createKey(int testType) {
+        try {
+            // Set the alias of the entry in Android KeyStore where the key will appear
+            // and the constrains (purposes) in the constructor of the Builder
+            KeyGenParameterSpec.Builder builder;
+            builder = new KeyGenParameterSpec.Builder(getKeyName(testType),
+                    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
+                    .setUserAuthenticationRequired(true)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
+            if (testType == LOCKSCREEN) {
+                // Require that the user unlocked the lockscreen in the last 5 seconds
+                builder.setUserAuthenticationValidityDurationSeconds(
+                        AUTHENTICATION_DURATION_SECONDS);
+            }
+            KeyGenerator keyGenerator = KeyGenerator.getInstance(
+                    KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME);
+            keyGenerator.init(builder.build());
+            keyGenerator.generateKey();
+        } catch (NoSuchAlgorithmException | NoSuchProviderException
+                | InvalidAlgorithmParameterException e) {
+            throw new RuntimeException("Failed to create a symmetric key", e);
+        }
+    }
+
+    private SecretKey loadSecretKey(int testType) {
+        try {
+            KeyStore keyStore = KeyStore.getInstance(KEYSTORE_NAME);
+            keyStore.load(null);
+            return (SecretKey) keyStore.getKey(getKeyName(testType), null);
+        } catch (UnrecoverableKeyException  | CertificateException |KeyStoreException | IOException
+                | NoSuchAlgorithmException e) {
+            throw new RuntimeException("Failed to load a symmetric key", e);
+        }
+    }
+
+    private boolean tryEncryptWithLockscreenKey() {
+        try {
+            // Try encrypting something, it will only work if the user authenticated within
+            // the last AUTHENTICATION_DURATION_SECONDS seconds.
+            Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
+            cipher.init(Cipher.ENCRYPT_MODE, loadSecretKey(LOCKSCREEN));
+            cipher.doFinal(SECRET_BYTE_ARRAY);
+            return true;
+        } catch (UserNotAuthenticatedException e) {
+            // User is not authenticated, let's authenticate with device credentials.
+            return false;
+        } catch (KeyPermanentlyInvalidatedException e) {
+            // This happens if the lock screen has been disabled or reset after the key was
+            // generated.
+            createKey(LOCKSCREEN);
+            showToast("Set up lockscreen after test ran. Retry the test.");
+            return false;
+        } catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException
+                | NoSuchPaddingException | NoSuchAlgorithmException e) {
+            throw new RuntimeException("Encrypt with lockscreen-bound key failed", e);
+        }
+    }
+
+    private Cipher initFingerprintEncryptionCipher() {
+        try {
+            Cipher cipher =  Cipher.getInstance(CIPHER_TRANSFORMATION);
+            cipher.init(Cipher.ENCRYPT_MODE, loadSecretKey(FINGERPRINT));
+            return cipher;
+        } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
+            return null;
+        } catch (KeyPermanentlyInvalidatedException e) {
+            // This happens if the lock screen has been disabled or reset after the key was
+            // generated after the key was generated.
+            createKey(FINGERPRINT);
+            showToast("Set up lockscreen after test ran. Retry the test.");
+            return null;
+        } catch (InvalidKeyException e) {
+            throw new RuntimeException("Init cipher with fingerprint-bound key failed", e);
+        }
+    }
+
+    private boolean tryEncryptWithFingerprintKey(Cipher cipher) {
+
+        try {
+            cipher.doFinal(SECRET_BYTE_ARRAY);
+            return true;
+        } catch (IllegalBlockSizeException e) {
+            // Cannot encrypt, key is unavailable
+            return false;
+        } catch (BadPaddingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    protected void handleActivityResult(int requestCode, int resultCode, Intent data) {
+        switch (requestCode) {
+            case CONFIRM_CREDENTIALS_REQUEST_CODE:
+                if (resultCode == RESULT_OK) {
+                    if (tryEncryptWithLockscreenKey()) {
+                        setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_PASSED);
+                    } else {
+                        showToast("Test failed. Key not accessible after auth");
+                        setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                    }
+                } else {
+                    showToast("Lockscreen challenge canceled.");
+                    setTestResult(mLockScreenBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                }
+                break;
+            default:
+                super.handleActivityResult(requestCode, resultCode, data);
+        }
+    }
+
+    private void showToast(String message) {
+        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
+    }
+
+    public class FingerprintAuthDialogFragment extends DialogFragment {
+
+        private CancellationSignal mCancellationSignal;
+        private FingerprintManagerCallback mFingerprintManagerCallback;
+        private boolean mSelfCancelled;
+
+        class FingerprintManagerCallback extends FingerprintManager.AuthenticationCallback {
+            @Override
+            public void onAuthenticationError(int errMsgId, CharSequence errString) {
+                if (!mSelfCancelled) {
+                    showToast(errString.toString());
+                }
+            }
+
+            @Override
+            public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+                showToast(helpString.toString());
+            }
+
+            @Override
+            public void onAuthenticationFailed() {
+                showToast(getString(R.string.sec_fp_auth_failed));
+            }
+
+            @Override
+            public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
+                if (tryEncryptWithFingerprintKey(mFingerprintCipher)) {
+                    showToast("Test passed.");
+                    setTestResult(mFingerprintBoundKeyTest, TestResult.TEST_RESULT_PASSED);
+                } else {
+                    showToast("Test failed. Key not accessible after auth");
+                    setTestResult(mFingerprintBoundKeyTest, TestResult.TEST_RESULT_FAILED);
+                }
+                FingerprintAuthDialogFragment.this.dismiss();
+            }
+        }
+
+        @Override
+        public void onDismiss(DialogInterface dialog) {
+            mCancellationSignal.cancel();
+            mSelfCancelled = true;
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            mCancellationSignal = new CancellationSignal();
+            mSelfCancelled = false;
+            mFingerprintManagerCallback = new FingerprintManagerCallback();
+            mFingerprintManager.authenticate(new FingerprintManager.CryptoObject(mFingerprintCipher),
+                    mCancellationSignal, 0, mFingerprintManagerCallback, null);
+            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+            builder.setMessage(R.string.sec_fp_dialog_message);
+            return builder.create();
+        }
+
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index 0200a4f..b129665 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -19,6 +19,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
@@ -59,7 +60,9 @@
     private DialogTestListItem mProfileAccountVisibleTest;
     private DialogTestListItem mDeviceAdminVisibleTest;
     private DialogTestListItem mWorkAppVisibleTest;
-    private DialogTestListItem mCrossProfileIntentFiltersTest;
+    private DialogTestListItem mCrossProfileIntentFiltersTestFromPersonal;
+    private DialogTestListItem mCrossProfileIntentFiltersTestFromWork;
+    private DialogTestListItem mAppLinkingTest;
     private DialogTestListItem mDisableNonMarketTest;
     private DialogTestListItem mEnableNonMarketTest;
     private DialogTestListItem mWorkNotificationBadgedTest;
@@ -78,6 +81,7 @@
     private DialogTestListItem mCrossProfileAudioCaptureSupportTest;
     private TestListItem mKeyguardDisabledFeaturesTest;
     private DialogTestListItem mDisableNfcBeamTest;
+    private TestListItem mAuthenticationBoundKeyTest;
 
     public ByodFlowTestActivity() {
         super(R.layout.provisioning_byod,
@@ -264,20 +268,39 @@
                 R.string.provisioning_byod_print_settings_instruction,
                 new Intent(Settings.ACTION_PRINT_SETTINGS));
 
-        Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
+        Intent intent = new Intent(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_WORK);
+        intent.putExtra(CrossProfileTestActivity.EXTRA_STARTED_FROM_WORK, false);
         Intent chooser = Intent.createChooser(intent,
                 getResources().getString(R.string.provisioning_cross_profile_chooser));
-        mCrossProfileIntentFiltersTest = new DialogTestListItem(this,
-                R.string.provisioning_byod_cross_profile,
-                "BYOD_CrossProfileIntentFiltersTest",
-                R.string.provisioning_byod_cross_profile_instruction,
+        mCrossProfileIntentFiltersTestFromPersonal = new DialogTestListItem(this,
+                R.string.provisioning_byod_cross_profile_from_personal,
+                "BYOD_CrossProfileIntentFiltersTestFromPersonal",
+                R.string.provisioning_byod_cross_profile_from_personal_instruction,
                 chooser);
 
+        mCrossProfileIntentFiltersTestFromWork = new DialogTestListItem(this,
+                R.string.provisioning_byod_cross_profile_from_work,
+                "BYOD_CrossProfileIntentFiltersTestFromWork",
+                R.string.provisioning_byod_cross_profile_from_work_instruction,
+                new Intent(ByodHelperActivity.ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG));
+
+        mAppLinkingTest = new DialogTestListItem(this,
+                R.string.provisioning_app_linking,
+                "BYOD_AppLinking",
+                R.string.provisioning_byod_app_linking_instruction,
+                new Intent(ByodHelperActivity.ACTION_TEST_APP_LINKING_DIALOG));
+
         mKeyguardDisabledFeaturesTest = TestListItem.newTest(this,
                 R.string.provisioning_byod_keyguard_disabled_features,
                 KeyguardDisabledFeaturesActivity.class.getName(),
                 new Intent(this, KeyguardDisabledFeaturesActivity.class), null);
 
+        mAuthenticationBoundKeyTest = TestListItem.newTest(this,
+                R.string.provisioning_byod_auth_bound_key,
+                AuthenticationBoundKeyTestActivity.class.getName(),
+                new Intent(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST),
+                null);
+
         // Test for checking if the required intent filters are set during managed provisioning.
         mIntentFiltersTest = new DialogTestListItem(this,
                 R.string.provisioning_byod_cross_profile_intent_filters,
@@ -287,7 +310,7 @@
                 checkIntentFilters();
             }
         };
-        
+
         Intent permissionCheckIntent = new Intent(
                 PermissionLockdownTestActivity.ACTION_MANAGED_PROFILE_CHECK_PERMISSION_LOCKDOWN);
         mPermissionLockdownTest = new DialogTestListItem(this,
@@ -314,12 +337,15 @@
         adapter.add(mDataUsageSettingsVisibleTest);
         adapter.add(mPrintSettingsVisibleTest);
 
-        adapter.add(mCrossProfileIntentFiltersTest);
+        adapter.add(mCrossProfileIntentFiltersTestFromPersonal);
+        adapter.add(mCrossProfileIntentFiltersTestFromWork);
+        adapter.add(mAppLinkingTest);
         adapter.add(mDisableNonMarketTest);
         adapter.add(mEnableNonMarketTest);
         adapter.add(mIntentFiltersTest);
         adapter.add(mPermissionLockdownTest);
         adapter.add(mKeyguardDisabledFeaturesTest);
+        adapter.add(mAuthenticationBoundKeyTest);
 
         if (canResolveIntent(ByodHelperActivity.getCaptureImageIntent())) {
             // Capture image intent can be resolved in primary profile, so test.
@@ -495,7 +521,8 @@
             ByodHelperActivity.class.getName(),
             WorkNotificationTestActivity.class.getName(),
             WorkStatusTestActivity.class.getName(),
-            PermissionLockdownTestActivity.ACTIVITY_ALIAS
+            PermissionLockdownTestActivity.ACTIVITY_ALIAS,
+            AuthenticationBoundKeyTestActivity.class.getName()
         };
         for (String component : components) {
             getPackageManager().setComponentEnabledSetting(new ComponentName(this, component),
@@ -503,4 +530,5 @@
                     PackageManager.DONT_KILL_APP);
         }
     }
+
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 3d7d42d..9ea5061 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -27,6 +27,7 @@
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.UserManager;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.support.v4.content.FileProvider;
@@ -84,6 +85,18 @@
     public static final String ACTION_CHECK_INTENT_FILTERS =
             "com.android.cts.verifier.managedprovisioning.action.CHECK_INTENT_FILTERS";
 
+    // Primary -> managed intent: will send a cross profile intent and check if the user sees an
+    // intent picker dialog and can open the apps.
+    public static final String ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG =
+            "com.android.cts.verifier.managedprovisioning.action.TEST_CROSS_PROFILE_INTENTS_DIALOG";
+
+    // Primary -> managed intent: will send an app link intent and check if the user sees a
+    // dialog and can open the apps. This test is extremely similar to
+    // ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG, but the intent used is a web intent, and there is
+    // some behavior which is specific to web intents.
+    public static final String ACTION_TEST_APP_LINKING_DIALOG =
+            "com.android.cts.verifier.managedprovisioning.action.TEST_APP_LINKING_DIALOG";
+
     public static final int RESULT_FAILED = RESULT_FIRST_USER;
 
     private static final int REQUEST_INSTALL_PACKAGE = 1;
@@ -211,6 +224,16 @@
             startActivity(testNfcBeamIntent);
             finish();
             return;
+        } else if (action.equals(ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG)) {
+            sendIntentInsideChooser(new Intent(
+                    CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL));
+        } else if (action.equals(ACTION_TEST_APP_LINKING_DIALOG)) {
+            mDevicePolicyManager.addUserRestriction(
+                    DeviceAdminTestReceiver.getReceiverComponentName(),
+                    UserManager.ALLOW_PARENT_PROFILE_APP_LINKING);
+            Intent toSend = new Intent(Intent.ACTION_VIEW);
+            toSend.setData(Uri.parse("http://com.android.cts.verifier"));
+            sendIntentInsideChooser(toSend);
         }
         // This activity has no UI and is only used to respond to CtsVerifier in the primary side.
         finish();
@@ -346,6 +369,13 @@
                 DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
     }
 
+    private void sendIntentInsideChooser(Intent toSend) {
+        toSend.putExtra(CrossProfileTestActivity.EXTRA_STARTED_FROM_WORK, true);
+        Intent chooser = Intent.createChooser(toSend,
+                getResources().getString(R.string.provisioning_cross_profile_chooser));
+        startActivity(chooser);
+    }
+
     @Override
     public void onDialogClose() {
         finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
index 6c38e12..3f316f21 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CrossProfileTestActivity.java
@@ -35,7 +35,12 @@
  */
 public class CrossProfileTestActivity extends Activity {
     // Intent for app in both profiles
-    public static final String ACTION_CROSS_PROFILE = "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE";
+    public static final String ACTION_CROSS_PROFILE_TO_PERSONAL =
+            "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_PERSONAL";
+    public static final String ACTION_CROSS_PROFILE_TO_WORK =
+            "com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_WORK";
+    public static final String EXTRA_STARTED_FROM_WORK
+            = "com.android.cts.verifier.managedprovisioning.STARTED_FROM_WORK";
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -45,9 +50,15 @@
 
         // Check if we are running in the work or personal side, by testing if currently we are the
         // profile owner or not.
-        textView.setText(isProfileOwner() ? R.string.provisioning_byod_cross_profile_app_work
-                : R.string.provisioning_byod_cross_profile_app_personal);
-
+        boolean inWorkProfile = isProfileOwner();
+        boolean startedFromWork = getIntent().getBooleanExtra(EXTRA_STARTED_FROM_WORK, false);
+        if (inWorkProfile && !startedFromWork) {
+            textView.setText(R.string.provisioning_byod_cross_profile_app_work);
+        } else if (!inWorkProfile && startedFromWork) {
+            textView.setText(R.string.provisioning_byod_cross_profile_app_personal);
+        } else { // started from the same side we're currently running in
+            textView.setText(R.string.provisioning_byod_cross_profile_app_ctsverifier);
+        }
         findViewById(R.id.button_finish).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index 008091b..ed6b5eb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -64,7 +64,9 @@
             filter.addAction(ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES);
             filter.addAction(ByodHelperActivity.ACTION_LOCKNOW);
             filter.addAction(ByodHelperActivity.ACTION_TEST_NFC_BEAM);
-            filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
+            filter.addAction(ByodHelperActivity.ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG);
+            filter.addAction(ByodHelperActivity.ACTION_TEST_APP_LINKING_DIALOG);
+            filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_WORK);
             filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION);
             filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN);
             filter.addAction(WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION);
@@ -72,12 +74,14 @@
             filter.addAction(WorkStatusTestActivity.ACTION_WORK_STATUS_ICON);
             filter.addAction(
                     PermissionLockdownTestActivity.ACTION_MANAGED_PROFILE_CHECK_PERMISSION_LOCKDOWN);
+            filter.addAction(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST);
             dpm.addCrossProfileIntentFilter(getWho(context), filter,
                     DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
 
             // Work -> primary direction
             filter = new IntentFilter();
             filter.addAction(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS);
+            filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL);
             dpm.addCrossProfileIntentFilter(getWho(context), filter,
                     DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java
new file mode 100644
index 0000000..43f293a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/AppLinkTestActivity.java
@@ -0,0 +1,113 @@
+/*
+ * 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.verifier.tv;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.media.tv.TvContract;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.cts.verifier.R;
+
+/**
+ * Tests for verifying TV app behavior for TV app-link.
+ */
+public class AppLinkTestActivity extends TvAppVerifierActivity implements View.OnClickListener {
+    private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
+
+    private boolean mSelectAppLinkItemPassed;
+    private View mSelectAppLinkItem;
+    private View mVerifyAppLinkIntentItem;
+    private View mVerifyAppLinkCardItem;
+
+    Runnable mSelectAppLinkFailCallback;
+
+    @Override
+    public void onClick(View v) {
+        final View postTarget = getPostTarget();
+
+        if (containsButton(mSelectAppLinkItem, v)) {
+            Intent tvAppIntent = null;
+            String[] projection = { TvContract.Channels._ID };
+            try (Cursor cursor = getContentResolver().query(
+                    TvContract.buildChannelsUriForInput(MockTvInputService.getInputId(this)),
+                    projection, null, null, null)) {
+                if (cursor != null && cursor.moveToNext()) {
+                    tvAppIntent = new Intent(Intent.ACTION_VIEW,
+                            TvContract.buildChannelUri(cursor.getLong(0)));
+                }
+            }
+            if (tvAppIntent == null) {
+                Toast.makeText(this, R.string.tv_channel_not_found, Toast.LENGTH_SHORT).show();
+                return;
+            }
+
+            mSelectAppLinkFailCallback = new Runnable() {
+                @Override
+                public void run() {
+                    mSelectAppLinkItemPassed = false;
+                    setPassState(mSelectAppLinkItem, false);
+                    setPassState(mVerifyAppLinkIntentItem, false);
+                }
+            };
+            postTarget.postDelayed(mSelectAppLinkFailCallback, TIMEOUT_MS);
+            mSelectAppLinkItemPassed = true;
+            setPassState(mSelectAppLinkItem, true);
+
+            startActivity(tvAppIntent);
+        } else if (containsButton(mVerifyAppLinkCardItem, v)) {
+            setPassState(mVerifyAppLinkCardItem, true);
+            getPassButton().setEnabled(true);
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        if (mSelectAppLinkItemPassed
+                && TextUtils.equals(MockTvInputSetupActivity.APP_LINK_TEST_VALUE,
+                        intent.getStringExtra(MockTvInputSetupActivity.APP_LINK_TEST_KEY))) {
+            getPostTarget().removeCallbacks(mSelectAppLinkFailCallback);
+            setPassState(mVerifyAppLinkIntentItem, true);
+            setButtonEnabled(mVerifyAppLinkCardItem, true);
+        }
+    }
+
+    @Override
+    protected void createTestItems() {
+        mSelectAppLinkItem = createUserItem(R.string.tv_app_link_test_select_app_link,
+                R.string.tv_launch_tv_app, this);
+        setButtonEnabled(mSelectAppLinkItem, true);
+        mVerifyAppLinkIntentItem = createAutoItem(
+                R.string.tv_app_link_test_verify_link_clicked);
+        mVerifyAppLinkCardItem = createUserItem(R.string.tv_input_link_test_verify_link_interface,
+                android.R.string.yes, this);
+        TextView instructions = (TextView) mVerifyAppLinkCardItem.findViewById(R.id.instructions);
+        Drawable image = getDrawable(R.drawable.app_link_img);
+        image.setBounds(0, 0, 317, 241);
+        instructions.setCompoundDrawablePadding(10);
+        instructions.setCompoundDrawables(image, null, null, null);
+    }
+
+    @Override
+    protected void setInfoResources() {
+        setInfoResources(R.string.tv_app_link_test, R.string.tv_app_link_test_info, -1);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
index c05b753..43ed7da 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSetupActivity.java
@@ -17,9 +17,12 @@
 package com.android.cts.verifier.tv;
 
 import android.app.Activity;
+import android.content.ComponentName;
 import android.content.ContentUris;
 import android.content.ContentValues;
+import android.content.Intent;
 import android.database.Cursor;
+import android.graphics.Color;
 import android.media.tv.TvContract;
 import android.media.tv.TvContract.Programs;
 import android.media.tv.TvInputInfo;
@@ -28,6 +31,8 @@
 import android.util.Pair;
 import android.view.View;
 
+import com.android.cts.verifier.R;
+
 import java.util.ArrayList;
 
 public class MockTvInputSetupActivity extends Activity {
@@ -38,6 +43,10 @@
 
     /* package-private */ static final String PROGRAM_TITLE = "Dummy Program";
     /* package-private */ static final String PROGRAM_DESCRIPTION = "Dummy Program Description";
+
+    /* package-private */ static final String APP_LINK_TEST_KEY = "app_link_test_key";
+    /* package-private */ static final String APP_LINK_TEST_VALUE = "app_link_test_value";
+    private static final String APP_LINK_TEXT = "Cts App-Link Text";
     private static final long PROGRAM_LENGTH_MILLIS = 60 * 60 * 1000;
     private static final int PROGRAM_COUNT = 24;
 
@@ -69,6 +78,18 @@
             values.put(TvContract.Channels.COLUMN_INPUT_ID, inputId);
             values.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, CHANNEL_NUMBER);
             values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, CHANNEL_NAME);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_TEXT, APP_LINK_TEXT);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_COLOR, Color.RED);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_ICON_URI,
+                    "android.resource://" + getPackageName() + "/" + R.drawable.icon);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_POSTER_ART_URI,
+                    "android.resource://" + getPackageName() + "/" + R.raw.sns_texture);
+            Intent appLinkIntentUri = new Intent(this, AppLinkTestActivity.class);
+            appLinkIntentUri.putExtra(APP_LINK_TEST_KEY, APP_LINK_TEST_VALUE);
+            appLinkIntentUri.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
+            values.put(TvContract.Channels.COLUMN_APP_LINK_INTENT_URI,
+                    appLinkIntentUri.toUri(Intent.URI_INTENT_SCHEME));
+
             Uri channelUri = getContentResolver().insert(uri, values);
             // If the channel's ID happens to be zero, we add another and delete the one.
             if (ContentUris.parseId(channelUri) == 0) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
index 12e9652..acab18e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
@@ -35,8 +35,6 @@
 public abstract class TvAppVerifierActivity extends PassFailButtons.Activity {
     private static final String TAG = "TvAppVerifierActivity";
 
-    private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
-
     private LayoutInflater mInflater;
     private ViewGroup mItemList;
     private View mPostTarget;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
index 06f4f6f..e8e2cee 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
@@ -25,8 +25,6 @@
 
 import com.android.cts.verifier.R;
 
-import java.util.List;
-
 /**
  * Tests for verifying TV app behavior for third-party TV input apps.
  */
@@ -131,7 +129,7 @@
         mGoToEpgItem = createUserItem(R.string.tv_input_discover_test_go_to_epg,
                 R.string.tv_launch_epg, this);
         mVerifyEpgItem = createUserItem(R.string.tv_input_discover_test_verify_epg,
-                R.string.tv_input_discover_test_yes, this);
+                android.R.string.yes, this);
     }
 
     @Override
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
index 70414ca..2ae2e10 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
@@ -294,7 +294,7 @@
     private LocalVolumeInfo getAdoptionVolume() throws Exception {
         String[] lines = null;
         int attempt = 0;
-        while (attempt++ < 5) {
+        while (attempt++ < 15) {
             lines = getDevice().executeShellCommand("sm list-volumes private").split("\n");
             for (String line : lines) {
                 final LocalVolumeInfo info = new LocalVolumeInfo(line.trim());
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 345279f..f15f6b0 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -262,6 +262,13 @@
   bug: 23008511
 },
 {
+  description: "Light status bar CTS coming in late",
+  names: [
+    "com.android.cts.systemui.LightStatusBarTests#testLightStatusBarIcons"
+  ],
+  bug: 23427621
+},
+{
   description: "known failures",
   names: [
     "android.hardware.cts.SensorBatchingTests#testAccelerometer_50hz_batching",
diff --git a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java b/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
index a86a707..241535e 100644
--- a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
+++ b/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
@@ -16,6 +16,7 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.cts.jank.leanback.IntentKeys;
 import android.os.SystemClock;
 import android.support.test.jank.GfxMonitor;
@@ -40,9 +41,30 @@
     private final static String JAVA_PACKAGE = "android.cts.jank.leanback.ui";
     private final static String CLASS = JAVA_PACKAGE + ".MainActivity";
 
+    private boolean shouldSkip() {
+	PackageManager packageManager =
+                getInstrumentation().getTargetContext().getPackageManager();
+        if (!packageManager.hasSystemFeature(
+                PackageManager.FEATURE_LEANBACK)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected void runTest() throws Throwable {
+        if (shouldSkip()) {
+            return;
+        }
+        super.runTest();
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        if (shouldSkip()) {
+            return;
+        }
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setComponent(new ComponentName(APP_PACKAGE, CLASS));
 
diff --git a/tests/tests/netlegacy22/api/Android.mk b/tests/netlegacy22.api/Android.mk
similarity index 100%
rename from tests/tests/netlegacy22/api/Android.mk
rename to tests/netlegacy22.api/Android.mk
diff --git a/tests/tests/netlegacy22/api/AndroidManifest.xml b/tests/netlegacy22.api/AndroidManifest.xml
similarity index 92%
rename from tests/tests/netlegacy22/api/AndroidManifest.xml
rename to tests/netlegacy22.api/AndroidManifest.xml
index d243e45..f13805c 100644
--- a/tests/tests/netlegacy22/api/AndroidManifest.xml
+++ b/tests/netlegacy22.api/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.net.legacy22">
+    package="com.android.cts.netlegacy22.api">
 
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -30,7 +30,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.net.legacy22"
+                     android:targetPackage="com.android.cts.netlegacy22.api"
                      android:label="CTS tests of legacy android.net APIs as of API 22">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/netlegacy22/api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java b/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
similarity index 84%
rename from tests/tests/netlegacy22/api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
rename to tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
index 8a9002b..1836f06 100644
--- a/tests/tests/netlegacy22/api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
+++ b/tests/netlegacy22.api/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
@@ -85,24 +85,58 @@
                 ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
     }
 
-    private void checkSourceAddress(String addrString, int type) throws Exception {
-        DatagramSocket d = new DatagramSocket();
-        d.connect(InetAddress.getByName(addrString), 7);
-        InetAddress localAddress = d.getLocalAddress();
-
+    // Returns a list of all the IP addresses for all the networks of a given legacy type. We can't
+    // just fetch the IP addresses for that type because there is no public getLinkProperties API
+    // that takes a legacy type.
+    private List<InetAddress> getIpAddresses(int type) {
+        ArrayList<InetAddress> addresses = new ArrayList<>();
         Network[] networks = mCm.getAllNetworks();
         for (int i = 0; i < networks.length; i++) {
             NetworkInfo ni = mCm.getNetworkInfo(networks[i]);
             if (ni != null && ni.getType() == type) {
+                // This does not include IP addresses on stacked interfaces (e.g., 464xlat), because
+                // there is no public API that will return them.
                 LinkProperties lp = mCm.getLinkProperties(networks[i]);
                 for (LinkAddress address : lp.getLinkAddresses()) {
-                    if (address.getAddress().equals(localAddress)) {
-                        return;
-                    }
+                    addresses.add(address.getAddress());
                 }
             }
         }
-        fail("Local address " + localAddress + " not assigned to any network of type " + type);
+        return addresses;
+    }
+
+    private boolean hasIPv4(int type) {
+        for (InetAddress address : getIpAddresses(type)) {
+            if (address instanceof Inet4Address) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void checkSourceAddress(String addrString, int type) throws Exception {
+        // The public requestRouteToHost API only supports IPv4, but it will not return failure if
+        // the network does not have an IPv4 address. So don't check that it's working unless we
+        // know that the network has an IPv4 address. Note that it's possible that the network will
+        // have an IPv4 address but we don't know about it, because the IPv4 address might be on a
+        // stacked interface and we wouldn't be able to see it.
+        if (!hasIPv4(type)) {
+            Log.d(TAG, "Not checking source address on network type " + type + ", no IPv4 address");
+            return;
+        }
+
+        DatagramSocket d = new DatagramSocket();
+        d.connect(InetAddress.getByName(addrString), 7);
+        InetAddress localAddress = d.getLocalAddress();
+        String localAddrString = localAddress.getHostAddress();
+
+        Log.d(TAG, "Got source address " + localAddrString + " for destination " + addrString);
+
+        assertTrue(
+                "Local address " + localAddress + " not assigned to any network of type " + type,
+                getIpAddresses(type).contains(localAddress));
+
+        Log.d(TAG, "Source address " + localAddress + " found on network type " + type);
     }
 
     /** Test that hipri can be brought up when Wifi is enabled. */
@@ -127,7 +161,6 @@
         assertTrue("Couldn't requestRouteToHost using HIPRI.",
                 mCm.requestRouteToHost(TYPE_MOBILE_HIPRI, ipv4AddrToInt(HOST_ADDRESS1)));
 
-        try { Thread.sleep(1000); } catch(Exception e) {}
         checkSourceAddress(HOST_ADDRESS1, TYPE_MOBILE);
         checkSourceAddress(HOST_ADDRESS2, TYPE_WIFI);
 
diff --git a/tests/tests/netlegacy22/permission/Android.mk b/tests/netlegacy22.permission/Android.mk
similarity index 100%
rename from tests/tests/netlegacy22/permission/Android.mk
rename to tests/netlegacy22.permission/Android.mk
diff --git a/tests/tests/netlegacy22/permission/AndroidManifest.xml b/tests/netlegacy22.permission/AndroidManifest.xml
similarity index 89%
rename from tests/tests/netlegacy22/permission/AndroidManifest.xml
rename to tests/netlegacy22.permission/AndroidManifest.xml
index d407404..cd1d2ba 100644
--- a/tests/tests/netlegacy22/permission/AndroidManifest.xml
+++ b/tests/netlegacy22.permission/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.permission">
+    package="com.android.cts.netlegacy22.permission">
 
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <application>
@@ -41,8 +41,8 @@
         relies on hidden APIs.
     -->
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.permission"
-                     android:label="CTS tests of com.android.cts.permission">
+                     android:targetPackage="com.android.cts.netlegacy22.permission"
+                     android:label="CTS tests of legacy android.net permissions as of API 22">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java b/tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java
similarity index 100%
rename from tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java
rename to tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/ConnectivityManagerPermissionTest.java
diff --git a/tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java b/tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java
similarity index 100%
rename from tests/tests/netlegacy22/permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java
rename to tests/netlegacy22.permission/src/android/net/cts/legacy/api22/permission/NoNetworkStatePermissionTest.java
diff --git a/tests/tests/alarmclock/AndroidTest.xml b/tests/tests/alarmclock/AndroidTest.xml
index 1cdd7f4..aafdb61 100644
--- a/tests/tests/alarmclock/AndroidTest.xml
+++ b/tests/tests/alarmclock/AndroidTest.xml
@@ -17,7 +17,5 @@
     <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockService.apk" />
     <option name="run-command:run-command"
          value="settings put secure voice_interaction_service android.alarmclock.service/.MainInteractionService" />
-    <option name="run-command:teardown-command"
-         value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
     <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockTestCases.apk" />
 </configuration>
diff --git a/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java b/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java
index 4e5b4ce..0d434f2 100644
--- a/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java
+++ b/tests/tests/alarmclock/src/android/alarmclock/cts/AlarmClockTestBase.java
@@ -70,7 +70,7 @@
                 new IntentFilter(Utils.BROADCAST_INTENT + testCaseType.toString()));
     }
 
-    private boolean isIntentAupported(TestcaseType testCaseType) {
+    private boolean isIntentSupported(TestcaseType testCaseType) {
         Intent intent;
         switch (testCaseType) {
           case DISMISS_ALARM:
@@ -102,7 +102,7 @@
     protected String runTest(TestcaseType testCaseType) throws Exception {
         Log.i(TAG, "Begin Testing: " + testCaseType);
         // Make sure the corresponding intent is supported by the platform, before testing.
-        if (!isIntentAupported(testCaseType)) return Utils.COMPLETION_RESULT;
+        if (!isIntentSupported(testCaseType)) return Utils.COMPLETION_RESULT;
 
         if (!startTestActivity(testCaseType)) {
             fail("test activity start failed for testcase = " + testCaseType);
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
index c807e03..22f092a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
@@ -102,13 +102,13 @@
                 sensor.getMaximumRange() >= maxRange);
         double actualMinFrequency = SensorCtsHelper.getFrequency(sensor.getMaxDelay(),
                 TimeUnit.MICROSECONDS);
-        assertTrue(String.format("%s Min Frequency actual=%.2f expected=%dHz",
+        assertTrue(String.format("%s Min Frequency actual=%.2f expected=%.2fHz",
                     sensor.getName(), actualMinFrequency, minFrequency), actualMinFrequency <=
                 minFrequency + 0.1);
 
         double actualMaxFrequency = SensorCtsHelper.getFrequency(sensor.getMinDelay(),
                 TimeUnit.MICROSECONDS);
-        assertTrue(String.format("%s Max Frequency actual=%.2f expected=%dHz",
+        assertTrue(String.format("%s Max Frequency actual=%.2f expected=%.2fHz",
                     sensor.getName(), actualMaxFrequency, maxFrequency), actualMaxFrequency >=
                 maxFrequency - 0.1);
     }
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index f844b76..a0f7384 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -105,6 +105,7 @@
             public boolean onError(MediaPlayer mp, int what, int extra) {
                 assertTrue(mp == mMediaPlayer);
                 assertTrue("mediaserver process died", what != MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+                Log.w(LOG_TAG, "onError " + what);
                 return false;
             }
         });
@@ -122,7 +123,9 @@
         afd.close();
         mMediaPlayer.prepare();
         mMediaPlayer.start();
-        mOnCompletionCalled.waitForSignal();
+        if (!mOnCompletionCalled.waitForSignal(5000)) {
+            Log.w(LOG_TAG, "testIfMediaServerDied: Timed out waiting for Error/Completion");
+        }
         mMediaPlayer.release();
     }
 
diff --git a/tests/tests/os/jni/seccomp_sample_program.cpp b/tests/tests/os/jni/seccomp_sample_program.cpp
index 3c90196..3bc7da4 100644
--- a/tests/tests/os/jni/seccomp_sample_program.cpp
+++ b/tests/tests/os/jni/seccomp_sample_program.cpp
@@ -826,7 +826,7 @@
   {0x35, 0, 4, 0x76},
   {0x35, 0, 2, 0x79},
   {0x35, 0, 241, 0x7a},
-  {0x35, 240, 239, 0x7b},
+  {0x35, 240, 239, 0x7c},
   {0x35, 238, 239, 0x77},
   {0x35, 0, 2, 0x72},
   {0x35, 0, 236, 0x73},
diff --git a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
index 00cbfd8..fdc3058 100644
--- a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
+++ b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
@@ -17,6 +17,7 @@
 package android.security.cts;
 
 import android.os.IBinder;
+import android.os.DeadObjectException;
 import android.os.TransactionTooLargeException;
 import android.test.AndroidTestCase;
 import android.util.Log;
@@ -108,7 +109,7 @@
                     // probably not checking for DUMP.
                     throw e;
                 }
-            } catch (TransactionTooLargeException e) {
+            } catch (TransactionTooLargeException | DeadObjectException e) {
                 // SELinux likely prevented the dump - assume safe
                 continue;
             } finally {
diff --git a/tests/tests/netlegacy22/Android.mk b/tests/tests/systemui/Android.mk
similarity index 63%
rename from tests/tests/netlegacy22/Android.mk
rename to tests/tests/systemui/Android.mk
index 3174652..1a15fd2 100644
--- a/tests/tests/netlegacy22/Android.mk
+++ b/tests/tests/systemui/Android.mk
@@ -12,5 +12,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Build the API tests and the permissions tests using their own makefiles.
-include $(call all-subdir-makefiles)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsSystemUiTestCases
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/systemui/AndroidManifest.xml b/tests/tests/systemui/AndroidManifest.xml
new file mode 100644
index 0000000..bf5df5b
--- /dev/null
+++ b/tests/tests/systemui/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?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.systemui">
+    <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application>
+        <activity android:name=".LightStatusBarActivity"
+                android:theme="@android:style/Theme.Material.NoActionBar"></activity>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.systemui">
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java b/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java
new file mode 100644
index 0000000..626a179
--- /dev/null
+++ b/tests/tests/systemui/src/com/android/cts/systemui/ColorUtils.java
@@ -0,0 +1,68 @@
+/*
+ * 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.systemui;
+
+/**
+ * Copies of non-public {@link android.graphics.Color} APIs
+ */
+public class ColorUtils {
+
+    public static float brightness(int argb) {
+        int r = (argb >> 16) & 0xFF;
+        int g = (argb >> 8) & 0xFF;
+        int b = argb & 0xFF;
+
+        int V = Math.max(b, Math.max(r, g));
+
+        return (V / 255.f);
+    }
+
+    public static float hue(int argb) {
+        int r = (argb >> 16) & 0xFF;
+        int g = (argb >> 8) & 0xFF;
+        int b = argb & 0xFF;
+
+        int V = Math.max(b, Math.max(r, g));
+        int temp = Math.min(b, Math.min(r, g));
+
+        float H;
+
+        if (V == temp) {
+            H = 0;
+        } else {
+            final float vtemp = (float) (V - temp);
+            final float cr = (V - r) / vtemp;
+            final float cg = (V - g) / vtemp;
+            final float cb = (V - b) / vtemp;
+
+            if (r == V) {
+                H = cb - cg;
+            } else if (g == V) {
+                H = 2 + cr - cb;
+            } else {
+                H = 4 + cg - cr;
+            }
+
+            H /= 6.f;
+            if (H < 0) {
+                H++;
+            }
+        }
+
+        return H;
+    }
+}
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java
new file mode 100644
index 0000000..3722320
--- /dev/null
+++ b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarActivity.java
@@ -0,0 +1,58 @@
+/*
+ * 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.systemui;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+
+/**
+ * An activity that exercises SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+ */
+public class LightStatusBarActivity extends Activity {
+
+    private View mContent;
+
+    public void onCreate(Bundle bundle){
+        super.onCreate(bundle);
+
+        mContent = new View(this);
+        mContent.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT));
+        setContentView(mContent);
+    }
+
+    public void setLightStatusBar(boolean lightStatusBar) {
+        int vis = getWindow().getDecorView().getSystemUiVisibility();
+        if (lightStatusBar) {
+            vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+        } else {
+            vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+        }
+        getWindow().getDecorView().setSystemUiVisibility(vis);
+    }
+
+    public int getTop() {
+        return mContent.getLocationOnScreen()[1];
+    }
+
+    public int getWidth() {
+        return mContent.getWidth();
+    }
+}
diff --git a/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java
new file mode 100644
index 0000000..b5bfd51
--- /dev/null
+++ b/tests/tests/systemui/src/com/android/cts/systemui/LightStatusBarTests.java
@@ -0,0 +1,235 @@
+/*
+ * 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.systemui;
+
+import android.app.ActivityManager;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.support.test.InstrumentationRegistry;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Test for light status bar.
+ */
+public class LightStatusBarTests extends ActivityInstrumentationTestCase2<LightStatusBarActivity> {
+
+    public static final String TAG = "LightStatusBarTests";
+
+    public static final String DUMP_PATH = "/sdcard/lightstatustest.png";
+
+    public LightStatusBarTests() {
+        super(LightStatusBarActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // As the way to access Instrumentation is changed in the new runner, we need to inject it
+        // manually into ActivityInstrumentationTestCase2. ActivityInstrumentationTestCase2 will
+        // be marked as deprecated and replaced with ActivityTestRule.
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+    }
+
+    public void testLightStatusBarIcons() throws Throwable {
+        PackageManager pm = getInstrumentation().getContext().getPackageManager();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+                || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            // No status bar on TVs and watches.
+            return;
+        }
+
+        if (!ActivityManager.isHighEndGfx()) {
+            // non-highEndGfx devices don't do colored system bars.
+            return;
+        }
+
+        requestLightStatusBar(Color.RED /* background */);
+        Thread.sleep(1000);
+
+        Bitmap bitmap = takeStatusBarScreenshot();
+        Stats s = evaluateLightStatusBarBitmap(bitmap, Color.RED /* background */);
+        boolean success = false;
+
+        try {
+            assertMoreThan("Not enough background pixels", 0.3f,
+                    (float) s.backgroundPixels / s.totalPixels(),
+                    "Is the status bar background showing correctly (solid red)?");
+
+            assertMoreThan("Not enough pixels colored as in the spec", 0.1f,
+                    (float) s.iconPixels / s.foregroundPixels(),
+                    "Are the status bar icons colored according to the spec "
+                            + "(60% black and 24% black)?");
+
+            assertLessThan("Too many lighter pixels lighter than the background", 0.05f,
+                    (float) s.sameHueLightPixels / s.foregroundPixels(),
+                    "Are the status bar icons dark?");
+
+            assertLessThan("Too many pixels with a changed hue", 0.05f,
+                    (float) s.unexpectedHuePixels / s.foregroundPixels(),
+                    "Are the status bar icons color-free?");
+
+            success = true;
+        } finally {
+            if (!success) {
+                Log.e(TAG, "Dumping failed bitmap to " + DUMP_PATH);
+                dumpBitmap(bitmap);
+            }
+        }
+    }
+
+    private void assertMoreThan(String what, float expected, float actual, String hint) {
+        if (!(actual > expected)) {
+            fail(what + ": expected more than " + expected * 100 + "%, but only got " + actual * 100
+                    + "%; " + hint);
+        }
+    }
+
+    private void assertLessThan(String what, float expected, float actual, String hint) {
+        if (!(actual < expected)) {
+            fail(what + ": expected less than " + expected * 100 + "%, but got " + actual * 100
+                    + "%; " + hint);
+        }
+    }
+
+    private void requestLightStatusBar(final int background) throws Throwable {
+        final LightStatusBarActivity activity = getActivity();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.getWindow().setStatusBarColor(background);
+                activity.setLightStatusBar(true);
+            }
+        });
+    }
+
+    private static class Stats {
+        int backgroundPixels;
+        int iconPixels;
+        int sameHueDarkPixels;
+        int sameHueLightPixels;
+        int unexpectedHuePixels;
+
+        int totalPixels() {
+            return backgroundPixels + iconPixels + sameHueDarkPixels
+                    + sameHueLightPixels + unexpectedHuePixels;
+        }
+
+        int foregroundPixels() {
+            return iconPixels + sameHueDarkPixels
+                    + sameHueLightPixels + unexpectedHuePixels;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("{bg=%d, ic=%d, dark=%d, light=%d, bad=%d}",
+                    backgroundPixels, iconPixels, sameHueDarkPixels, sameHueLightPixels,
+                    unexpectedHuePixels);
+        }
+    }
+
+    private Stats evaluateLightStatusBarBitmap(Bitmap bitmap, int background) {
+        int iconColor = 0x99000000;
+        int iconPartialColor = 0x3d000000;
+
+        int mixedIconColor = mixSrcOver(background, iconColor);
+        int mixedIconPartialColor = mixSrcOver(background, iconPartialColor);
+
+        int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
+        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+        Stats s = new Stats();
+        float eps = 0.005f;
+
+        for (int c : pixels) {
+            if (c == background) {
+                s.backgroundPixels++;
+                continue;
+            }
+
+            // What we expect the icons to be colored according to the spec.
+            if (c == mixedIconColor || c == mixedIconPartialColor) {
+                s.iconPixels++;
+                continue;
+            }
+
+            // Due to anti-aliasing, there will be deviations from the ideal icon color, but it
+            // should still be mostly the same hue.
+            float hueDiff = Math.abs(ColorUtils.hue(background) - ColorUtils.hue(c));
+            if (hueDiff < eps || hueDiff > 1 - eps) {
+                // .. it shouldn't be lighter than the original background though.
+                if (ColorUtils.brightness(c) > ColorUtils.brightness(background)) {
+                    s.sameHueLightPixels++;
+                } else {
+                    s.sameHueDarkPixels++;
+                }
+                continue;
+            }
+
+            s.unexpectedHuePixels++;
+        }
+
+        return s;
+    }
+
+    private void dumpBitmap(Bitmap bitmap) {
+        FileOutputStream fileStream = null;
+        try {
+            fileStream = new FileOutputStream(DUMP_PATH);
+            bitmap.compress(Bitmap.CompressFormat.PNG, 85, fileStream);
+            fileStream.flush();
+        } catch (Exception e) {
+            Log.e(TAG, "Dumping bitmap failed.", e);
+        } finally {
+            if (fileStream != null) {
+                try {
+                    fileStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private int mixSrcOver(int background, int foreground) {
+        int bgAlpha = Color.alpha(background);
+        int bgRed = Color.red(background);
+        int bgGreen = Color.green(background);
+        int bgBlue = Color.blue(background);
+
+        int fgAlpha = Color.alpha(foreground);
+        int fgRed = Color.red(foreground);
+        int fgGreen = Color.green(foreground);
+        int fgBlue = Color.blue(foreground);
+
+        return Color.argb(fgAlpha + (255 - fgAlpha) * bgAlpha / 255,
+                    fgRed + (255 - fgAlpha) * bgRed / 255,
+                    fgGreen + (255 - fgAlpha) * bgGreen / 255,
+                    fgBlue + (255 - fgAlpha) * bgBlue / 255);
+    }
+
+    private Bitmap takeStatusBarScreenshot() {
+        Bitmap fullBitmap = getInstrumentation().getUiAutomation().takeScreenshot();
+        return Bitmap.createBitmap(fullBitmap, 0, 0,
+                getActivity().getWidth(), getActivity().getTop());
+    }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/MmsTest.java b/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
index 176c50c..e15b45f 100644
--- a/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/MmsTest.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.SystemClock;
 import android.telephony.SmsManager;
@@ -84,6 +85,7 @@
     private Random mRandom;
     private SentReceiver mSentReceiver;
     private TelephonyManager mTelephonyManager;
+    private PackageManager mPackageManager;
 
     private static class SentReceiver extends BroadcastReceiver {
         private final Object mLock;
@@ -164,15 +166,26 @@
         mRandom = new Random();
         mTelephonyManager =
                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        mPackageManager = mContext.getPackageManager();
     }
 
     public void testSendMmsMessage() {
-        if (!mTelephonyManager.isSmsCapable()) {
-            Log.i(TAG, "testSendMmsMessage skipped: not SMS capable");
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.i(TAG, "testSendMmsMessage skipped: no telephony available");
             return;
         }
 
         Log.i(TAG, "testSendMmsMessage");
+        // Prime the MmsService so that MMS config is loaded
+        final SmsManager smsManager = SmsManager.getDefault();
+        smsManager.getAutoPersisting();
+        // MMS config is loaded asynchronously. Wait a bit so it will be loaded.
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            // Ignore
+        }
+
         final Context context = getContext();
         // Register sent receiver
         mSentReceiver = new SentReceiver();
@@ -193,7 +206,7 @@
         // Send
         final PendingIntent pendingIntent = PendingIntent.getBroadcast(
                 context, 0, new Intent(ACTION_MMS_SENT), 0);
-        SmsManager.getDefault().sendMultimediaMessage(context,
+        smsManager.sendMultimediaMessage(context,
                 contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent);
         assertTrue(mSentReceiver.waitForSuccess(SENT_TIMEOUT));
         sendFile.delete();
diff --git a/tests/tests/voiceinteraction/AndroidTest.xml b/tests/tests/voiceinteraction/AndroidTest.xml
index 374c216..fa1ab70 100644
--- a/tests/tests/voiceinteraction/AndroidTest.xml
+++ b/tests/tests/voiceinteraction/AndroidTest.xml
@@ -19,7 +19,5 @@
     <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionApp.apk" />
     <option name="run-command:run-command"
          value="settings put secure voice_interaction_service android.voiceinteraction.service/.MainInteractionService" />
-    <option name="run-command:teardown-command"
-         value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
     <option name="cts-apk-installer:test-file-name" value="CtsVoiceInteractionTestCases.apk" />
 </configuration>
diff --git a/tests/tests/voicesettings/AndroidTest.xml b/tests/tests/voicesettings/AndroidTest.xml
index 0a3974d..e3be691 100644
--- a/tests/tests/voicesettings/AndroidTest.xml
+++ b/tests/tests/voicesettings/AndroidTest.xml
@@ -17,7 +17,5 @@
     <option name="cts-apk-installer:test-file-name" value="CtsVoiceSettingsService.apk" />
     <option name="run-command:run-command"
          value="settings put secure voice_interaction_service android.voicesettings.service/.MainInteractionService" />
-    <option name="run-command:teardown-command"
-         value="settings put secure voice_interaction_service com.google.android.googlequicksearchbox/com.google.android.voiceinteraction.GsaVoiceInteractionService" />
     <option name="cts-apk-installer:test-file-name" value="CtsVoiceSettingsTestCases.apk" />
 </configuration>
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
index 4597651..2d19162 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
@@ -16,6 +16,8 @@
 
 package android.voicesettings.cts;
 
+import static android.provider.Settings.ACTION_VOICE_CONTROL_AIRPLANE_MODE;
+
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.util.Log;
@@ -33,6 +35,9 @@
     }
 
     public void testAll() throws Exception {
+        if (!isIntentSupported(ACTION_VOICE_CONTROL_AIRPLANE_MODE)) {
+            return;
+        }
         int mode;
         try {
             mode = getMode();
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
index 3d1357a..6fe82a7 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/BatterySaverModeTest.java
@@ -16,6 +16,8 @@
 
 package android.voicesettings.cts;
 
+import static android.provider.Settings.ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE;
+
 import android.content.Context;
 import android.os.PowerManager;
 import android.util.Log;
@@ -30,6 +32,9 @@
     }
 
     public void testAll() throws Exception {
+        if (!isIntentSupported(ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE)) {
+            return;
+        }
         startTestActivity("BATTERYSAVER_MODE");
         boolean modeIsOn = isModeOn();
         Log.i(TAG, "Before testing, BATTERYSAVER_MODE is set to: " + modeIsOn);
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java b/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java
index 5386497..b355e7b 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/VoiceSettingsTestBase.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
@@ -57,6 +58,17 @@
         super.tearDown();
     }
 
+    protected boolean isIntentSupported(String intentStr) {
+        Intent intent = new Intent(intentStr);
+        final PackageManager manager = mContext.getPackageManager();
+        assertNotNull(manager);
+        if (manager.resolveActivity(intent, 0) == null) {
+            Log.i(TAG, "No Voice Activity found for the intent: " + intentStr);
+            return false;
+        }
+        return true;
+    }
+
     protected void startTestActivity(String intentSuffix) {
         Intent intent = new Intent();
         intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + intentSuffix);
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
index ca86918..b0ddf44 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
@@ -16,6 +16,7 @@
 
 package android.voicesettings.cts;
 
+import static android.provider.Settings.ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE;
 import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_ENABLED;
 import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_MINUTES;
 
@@ -39,6 +40,9 @@
     }
 
     public void testAll() throws Exception {
+        if (!isIntentSupported(ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE)) {
+            return;
+        }
         int mode;
         try {
             mode = getMode();
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index a048ddc..adb6a4e 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -492,6 +492,9 @@
       'android.voicesettings' : [
           'android.voicesettings.cts.ZenModeTest#testAll',
       ],
+      'com.android.cts.systemui' : [
+          'com.android.cts.systemui.LightStatusBarTests#testLightStatusBarIcons',
+      ],
       'com.android.cts.app.os' : [
           'com.android.cts.app.os.OsHostTests#testNonExportedActivities',
       ],